pipe2.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,160 行 · 第 1/3 页

C
1,160
字号
    rend_obj *  obj_poly1,
    rend_obj *  obj_poly2
) {
    point       edge1[2];
    point       edge2[2];
    int         num_pts1;
    int         num_pts2;
    int         curr_pt1;
    int         curr_pt2;
    polygon     *poly1;
    polygon     *poly2;
    int         num_crosses;
    visible_info *vis1;
    visible_info *vis2;

    vis1 = _rend_obj_get_vis( obj_poly1 );
    vis2 = _rend_obj_get_vis( obj_poly2 );
    poly1 = rend_obj_get_poly( obj_poly1 );
    poly2 = rend_obj_get_poly( obj_poly2 );

    num_pts1 = _polygon_get_num_pts( *poly1 );
    num_pts2 = _polygon_get_num_pts( *poly2 );

    /* start with the edge between point 0 and point (num_pts1-1) */
    edge1[0] = _polygon_get_pt( *poly1, num_pts1-1 );
    for (curr_pt1 = 0; curr_pt1 < num_pts1; curr_pt1++) {
        edge1[1] = _polygon_get_pt( *poly1, curr_pt1 );

        /* start with the edge between point 0 and point (num_pts2-1) */
        edge2[0] = _polygon_get_pt( *poly2, num_pts2-1 );
        for (curr_pt2 = 0; curr_pt2 < num_pts2; curr_pt2++) {
            edge2[1] = _polygon_get_pt( *poly2, curr_pt2 );

            if (proj_line_intersection( edge1, edge2 )) {
                return( TRUE );
            }

            edge2[0] = edge2[1];
        }

        edge1[0] = edge1[1];
    }

    /* either poly 1 is contained in poly 2 . . .       */

    num_crosses = 0;
    edge2[0] = _polygon_get_pt( *poly2, num_pts2-1 );
    edge2[1] = edge2[0];
    edge2[1].p[0] = vis1->min.p[0] - .1;
    edge1[0] = _polygon_get_pt( *poly1, num_pts1-1 );
    for (curr_pt1 = 0; curr_pt1 < num_pts1; curr_pt1++) {
        edge1[1] = _polygon_get_pt( *poly1, curr_pt1 );

        if (proj_line_intersection( edge1, edge2 )) {
            num_crosses += 1;
        }

        edge1[0] = edge1[1];
    }
    if( num_crosses % 2 == 1 ) {
        return( TRUE );
    }

    /* or poly 2 is contained in poly 1 . . .           */

    num_crosses = 0;
    edge2[0] = _polygon_get_pt( *poly1, num_pts1-1 );
    edge2[1] = edge2[0];
    edge2[1].p[0] = vis2->min.p[0] - .1;
    edge1[0] = _polygon_get_pt( *poly2, num_pts2-1 );
    for (curr_pt2 = 0; curr_pt2 < num_pts2; curr_pt2++) {
        edge1[1] = _polygon_get_pt( *poly2, curr_pt2 );

        if (proj_line_intersection( edge1, edge2 )) {
            num_crosses += 1;
        }
        edge1[0] = edge1[1];
    }
    if( num_crosses % 2 == 1 ) {
        return( TRUE );
    }

    /* or they are truly disjoint                       */
    return( FALSE );
}


static bool proj_overlap(
/***********************/
/* Tests whether the projection of obj1 and obj2 into the x-y plane overlaps */
/* NOTE: This function assumes that extent testing has been performed and */
/* that the extents do overlap */
    rend_obj *  obj1,
    rend_obj *  obj2
) {
    rend_type   type1;
    rend_type   type2;

    type1 = _rend_obj_get_type( obj1 );
    type2 = _rend_obj_get_type( obj2 );

    /* the extent for a point is the point itself so if the extents overlap */
    /* then the projections will overlap */
    if (type1 == REND_OBJ_PT || type2 == REND_OBJ_PT) {
        return( TRUE );
    }

    switch (type1) {
    case REND_OBJ_LINE:
        switch (type2) {
        case REND_OBJ_LINE:
            return( proj_overlap_ln_ln( obj1, obj2 ) );
            break;
        case REND_OBJ_POLY:
            return( proj_overlap_ln_poly( obj1, obj2 ) );
            break;
        }
        break;
    case REND_OBJ_POLY:
        switch (type2) {
        case REND_OBJ_LINE:
            return( proj_overlap_ln_poly( obj2, obj1 ) );
            break;
        case REND_OBJ_POLY:
            return( proj_overlap_poly_poly( obj1, obj2 ) );
            break;
        }
        break;
    }

    return( TRUE );
}


static bool test_for_overlap(
/***************************/
/* This function implements tests 1-5 for the depth-sort algorithm. */
    rend_obj *      qobj,           // p and q refer to names on p. 673
    rend_obj *      pobj
) {
    visible_info *  qvis;
    visible_info *  pvis;

    qvis = _rend_obj_get_vis( qobj );
    pvis = _rend_obj_get_vis( pobj );

    /* test 1 */
    if (!_extent_overlap( qvis, pvis, 0 )) {
        return( FALSE );
    }
    /* test 2 */
    if (!_extent_overlap( qvis, pvis, 1 )) {
        return( FALSE );
    }
    /* test 3 */
    if (far_half_space( pobj, qobj )) {
        return( FALSE );
    }
    /* test 4 */
    if (near_half_space( qobj, pobj )) {
        return( FALSE );
    }
    /* test 5 */
    if (!proj_overlap( qobj, pobj )) {
        return( FALSE );
    }
    return( TRUE );
}

static bool test_for_mtf(
/************************/
/* Tests whether it is safe to move qobj to before pobj in the list. */
/* mtf -- move to front */
/* This function impliments test 3' and 4' from the depth-sort alogorithm */
    rend_obj *      qobj,           // p and q refer to names on p. 673
    rend_obj *      pobj
) {
    /* test 3' */
    if (far_half_space( qobj, pobj )) {
        return( TRUE );
    }
    /* test 4' */
    if (near_half_space( pobj, qobj )) {
        return( TRUE );
    }
    return( FALSE );
}

static void get_first_unmarked(
/*****************************/
    rend_list *     list,
    rend_list_ref * ref
) {
    visible_info *  vis;

    _rend_list_first( list, ref );
    while (!_rend_list_is_after_last( list, *ref )) {
        vis = _rend_obj_get_vis( _rend_list_get_obj( list, *ref ) );
        if (!vis->mark) {
            return;
        }
        _rend_list_next( list, ref );
    }
}

static void split_object(
/***********************/
/* Split obj1 by the plane of obj2 and insert the pieces into list in proper */
/* z-min order after any marked objects. */
    rend_list *     list,
    rend_obj *      obj1,
    rend_obj *      obj2
) {
    vector          norm;   // plane of obj2
    rend_obj *      p;      // pieces of obj1 in local memory
    rend_obj *      g;      // in pipe memory
    rend_list_ref   start;  // for specifying the sublist to insert into
    rend_list_ref   end;
    int             i;

    norm = calculate_object_norm( obj2, obj1 );

    p = rend_obj_clip( obj1, norm );
    if (p != NULL) {
        g = rend_obj_dup( p );
        rend_obj_lfree( p );
        rend_obj_compute_vis_info( g );
        get_first_unmarked( list, &start );
        _rend_list_last( list, &end );
        rend_list_bin_insert( list, start, end, &g, compare_zmin );
    }

    /* Change the direction of the normal */
    for (i=0; i<4; i++) {
        norm.v[i] *= -1;
    }

    p = rend_obj_clip( obj1, norm );
    if (p != NULL) {
        g = rend_obj_dup( p );
        rend_obj_lfree( p );
        rend_obj_compute_vis_info( g );
        get_first_unmarked( list, &start );
        _rend_list_last( list, &end );
        rend_list_bin_insert( list, start, end, &g, compare_zmin );
    }
}

static void split_marked_object(
/******************************/
/* This routine determines which of obj1 or obj2 to split the splits it and */
/* inserts the pieces into list */
    rend_list *     list,
    rend_obj *      obj1,
    rend_obj *      obj2
) {

    if (check_half_space( obj1, obj2 ) == HALF_SPACE_NONE) {
        split_object( list, obj1, obj2 );
    } else if (check_half_space( obj2, obj1 ) == HALF_SPACE_NONE) {
        split_object( list, obj2, obj1 );
    } else {
        // Neither obj1 nor obj2 is split by the plane of the other so some
        // other splitting criterion should be applied to one of the objects
        // and the resulting pieces inserted into the list.
        // Since this case should not occur and I can't think of such a
        // criterion this case is considered a fatal error.
        WPI_INST                inst;
        inst = inst;
#ifdef PLAT_OS2
        _wpi_setanchorblock( HWND_DESKTOP, inst );
#endif
        _wpi_fatalappexit( inst, 0, "Internal wcgr error." );
    }
}

static void check_overlap(
/************************/
    rend_list *     list,
    rend_list_ref * dref            // reference to the candidate for drawing
) {
    rend_list_ref   cref;           // reference to the obj to check
    rend_obj *      dobj;
    rend_obj *      cobj;
    visible_info *  dvis;
    visible_info *  cvis;

    cref = *dref;
    _rend_list_next( list, &cref );
    /* note: a for loop is used here so the continue will work */
    for (; !_rend_list_is_after_last( list, cref );
            _rend_list_next( list, &cref ) ) {

        cobj = _rend_list_get_obj( list, cref );
        dobj = _rend_list_get_obj( list, *dref );
        cvis = _rend_obj_get_vis( cobj );
        dvis = _rend_obj_get_vis( dobj );

        /* Check if the objects overlap in z */
        if (dvis->max.p[2] < cvis->min.p[2]) {
            if (cvis->mark) {
                /* if the object is marked it is not in sorted order so */
                /* continue checking other objects in the list */
    /**/        continue;
            } else {
                /* if the object is not marked it is in sorted order in the */
                /* list so all objects later in the list have zmin >= zmin of */
                /* cobj so it is safe to draw dobj now */
    /**/        break;
            }
        }

        if (test_for_overlap( cobj, dobj )) {
            if (cvis->mark) {
                /* This case handles cyclical overlap which should not occur */
                /* in a 3d chart, but just in case ... */
                split_marked_object( list, dobj, cobj );
            } else {
                if (test_for_mtf( cobj, dobj )) {
                    /* mark cobj and move it to the front of the list */
                    cvis->mark = TRUE;
                    rend_list_delete( list, &cref );
                    _rend_list_first( list, &cref );
                    rend_list_insert( list, &cref, cobj, TRUE );
                } else {
                    /* ASSERT: dobj is not a point */
                    /* remove dref from list */
                    rend_list_delete( list, dref );
                    /* if we get here we know that dobj lies on both sides of */
                    /* the plane of cobj so split dobj by the plane of cobj */
                    /* and insert the pieces into the list in the proper spots*/
                    split_object( list, dobj, cobj );
                }
            }
            _rend_list_first( list, dref );
            cref = *dref;
        }
    }
}


#if 0
static void unmark_list(
/**********************/
    rend_list *     list
) {
    rend_list_ref   curr;
    visible_info *  vis;

    if (_rend_list_is_empty( list )) {
        return;
    }

    _rend_list_first( list, &curr );
    while (!_rend_list_is_after_last( list, curr )) {
        vis = _rend_obj_get_vis( _rend_list_get_obj( list, curr ) );
        vis->mark = FALSE;
        _rend_list_next( list, &curr );
    }
}
#endif

static void display_visible_surfaces(
/***********************************/
    rend_list *     list
) {
    rend_list_ref   curr_ref;       // reference to obj we wish to draw

//  compute_extents( list );
    rend_list_sort( list, compare_zmin );

    while (!_rend_list_is_empty( list )) {
        _rend_list_first( list, &curr_ref );
        check_overlap( list, &curr_ref );
        draw_illuminated_obj( _rend_list_get_obj( list, curr_ref ) );
        rend_list_delete( list, &curr_ref );
    }
}

extern void pipe3d_display(
/*************************/
    void
) {
    display_visible_surfaces( Pipe3dList );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?