pipeobj.c

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

C
1,446
字号
        return( obj->obj.poly.num_pts );
        break;
    case REND_OBJ_LINE:
        return( 2 );
        break;
    case REND_OBJ_PT:
        return( 1 );
        break;
    default:
        return( 0 );
        break;
    }
}

extern point rend_obj_get_pt(
/***************************/
    rend_obj *  obj,
    int         pt_num
) {
    point       pt;

    switch (obj->type) {
    case REND_OBJ_PT:
        if (pt_num == 0) {
            pt = obj->obj.pt;
        } else {
            pt = invalid_pt;
        }
        break;
    case REND_OBJ_LINE:
        switch (pt_num) {
        case 0:
            pt = obj->obj.line.start;
            break;
        case 1:
            pt = obj->obj.line.end;
            break;
        default:
            pt = invalid_pt;
            break;
        }
        break;
    case REND_OBJ_POLY:
        if (0 <= pt_num && pt_num < obj->obj.poly.num_pts) {
            pt = _polygon_get_pt( obj->obj.poly, pt_num );
        } else {
            pt = invalid_pt;
        }
        break;
    case REND_OBJ_SOLID:
        if (0 <= pt_num && pt_num < obj->obj.solid.pts.num_pts) {
            pt = obj->obj.solid.pts.pts[ pt_num ];
        } else {
            pt = invalid_pt;
        }
        break;
    default:
        pt = invalid_pt;
        break;
    }

    return( pt );
}

extern polygon * rend_obj_get_poly(
/*********************************/
    rend_obj *  obj
) {
    if (obj->type == REND_OBJ_POLY) {
        return( &obj->obj.poly );
    } else {
        return( NULL );
    }
}

extern line * rend_obj_get_line(
/******************************/
    rend_obj * obj
) {
    if( obj->type == REND_OBJ_LINE ) {
        return( &obj->obj.line );
    } else {
        return( NULL );
    }
}

#if 0
/* macroed */
extern rend_type rend_obj_get_type(
/*********************************/
    rend_obj *  obj
) {
    return( obj->type );
}
#endif

static point polygon_get_pt(
/**************************/
    polygon *   poly,
    int         pt_num
) {
    return( _polygon_get_pt( *poly, pt_num ) );
}

static void calc_norm_poly(
/*************************/
    polygon *   poly
) {
    int         i;

    poly->normal = calculate_normal_vector( poly->num_pts,
                                poly, (point(*)(void*,int))polygon_get_pt );
    /* since the the transformation has been applied, a normal is facing */
    /* the viewer if its z coordinate is positive */
    if( poly->normal.v[2] < 0. ) {
        for( i = 0; i < 4; i++ ) {
            poly->normal.v[i] *= -1.;
        }
    }
}

static point face_get_pt(
/***********************/
    face_pts *  side,
    int         pt_num
) {
    return( side->pts[ side->side->index[ pt_num ].pt_num ] );
}

static void calc_norm_solid(
/**************************/
    polyhedron *    solid
) {
    face *          curr_face;
    face_pts        side;

    side.pts = solid->pts.pts;

    for (curr_face = solid->faces.faces; curr_face < solid->faces.faces
                + solid->faces.num_faces; curr_face++) {
        side.side = curr_face;
        curr_face->normal = calculate_normal_vector( curr_face->num_pts,
                        &side, (point(*)(void*,int))face_get_pt );
    }
}

extern void rend_obj_calculate_normal(
/************************************/
    rend_obj *  obj
) {
    switch (obj->type) {
    case REND_OBJ_PT:
    case REND_OBJ_LINE:
        break;              // lines and points don't have normals
    case REND_OBJ_POLY:
        calc_norm_poly( &(obj->obj.poly) );
        break;
    case REND_OBJ_SOLID:
        calc_norm_solid( &(obj->obj.solid) );
        break;
    }
}

static bool inside(
/*****************/
    point   pt,
    vector  norm
) {
    float   result;

    result = _dot_prod_vp( norm, pt );

    return( result < FUZZY_ZERO );
}

static void output(
/*****************/
    point           pt,
    polygon *       poly,
    bool            edge,
    bool            force_pt
) {
    vertex_list *   pts;

    pts = poly->pts;

    pts->num_pts += 1;
    _renew( pts->pts, pts->num_pts );
    pts->pts[ pts->num_pts - 1 ] = pt;

    poly->num_pts += 1;
    _renew( poly->index, poly->num_pts );
    poly->index[ poly->num_pts - 1 ].pt_num = pts->num_pts - 1;
    poly->index[ poly->num_pts - 1 ].hilight_edge = edge;
    poly->index[ poly->num_pts - 1 ].force_rgn_pt = force_pt;
}

static bool intersect(
/********************/
/* The point of intersection between the line first to second and the plane */
/* defined by normal is place in inter. See Log Notes p. 1 */
/* Returns TRUE if the intersection point falls between first and second. */
    point   first,
    point   second,
    vector  normal,
    point * inter
) {
    float   t;
    float   denom;
    vector  p;
    int     i;

    for (i=0; i < 4; i++) {
        p.v[i] = second.p[i] - first.p[i];
    }

    denom = _dot_prod_vv( normal, p );
    if (fabs( denom ) < FUZZY_ZERO) {
        /* the lines are numerically parallel so set the point arbitraily */
        /* and return FALSE */
        for (i=0; i < 4; i++) {
            inter->p[i] = first.p[i];
        }
        return( FALSE );
    } else {
        t = - _dot_prod_vp( normal, first ) / denom;
    }

    for (i=0; i < 4; i++) {
        inter->p[i] = first.p[i] + t * p.v[i];
    }

    return( 0. <= t && t <= 1. );
}

static bool clip_3d_poly(
/***********************/
/*
clip the polygon defined by 'obj' against the bounding plane defined by
'normal' and return the resulting rend_obj in local memory. See
"Computer Graphics" by Foley, et. al. pp. 124-129. 'normal' is assumed to
be outward pointing.
Returns TRUE if the polygon is outside the clip plane.
*/
    polygon *   poly,
    polygon *   new_poly,
    vector      normal
) {
    point       s;          // starting point of current edge
    point       p;          // ending point
    point       i;          // intersection point of edge with plane
    int         pt_num;
    bool        edge_s;
    bool        edge_p;
    bool        force_p;

    new_poly->normal = poly->normal;
    new_poly->rgn_pt_iter = poly->rgn_pt_iter;

    s = _polygon_get_pt( *poly, poly->num_pts - 1 );
    edge_s = _polygon_edge_hilight( *poly, poly->num_pts - 1 );
    for (pt_num = 0; pt_num < poly->num_pts; pt_num++) {
        p = _polygon_get_pt( *poly, pt_num );
        edge_p = _polygon_edge_hilight( *poly, pt_num );
        force_p = _polygon_force_rgn_pt( *poly, pt_num );
        if (inside( p, normal)) {       // cases 1 and 4
            if (inside( s, normal )) {
                output( p, new_poly, edge_p, force_p ); // case 1
            } else {
                intersect( s, p, normal, &i );  // case 4
                output( i, new_poly, edge_s, FALSE );
                output( p, new_poly, edge_p, force_p );
            }
        } else {                        // cases 2 and 3
            if (inside( s, normal )) {          // case 2
                intersect( s, p, normal, &i );
                output( i, new_poly, FALSE, FALSE );
            }                                   // no action for case 3
        }
        s = p;
        edge_s = edge_p;
    }

    return( new_poly->num_pts == 0 );
}

static bool clip_3d_line(
/***********************/
    line *      in,
    line *      out,
    vector      normal
) {
    bool        start_in;
    bool        end_in;

    start_in = inside( in->start, normal );
    end_in = inside( in->end, normal );

    if (start_in) {
        out->start = in->start;
    } else {
        intersect( in->start, in->end, normal, &(out->start) );
    }
    if (end_in) {
        out->end = in->end;
    } else {
        intersect( in->start, in->end, normal, &(out->end) );
    }

    return (!(start_in || end_in));
}

extern rend_obj * rend_obj_clip(
/******************************/
/* Clip obj by the plane defined by norm and put the result in memory */
/* allocated by alloc and return a pointer to it */
/* NOTE: points are not handled by this algorithm as they can't be clipped */
    rend_obj *  obj,
    vector      norm
) {
    rend_obj *  new_obj;

    switch (obj->type) {
    case REND_OBJ_LINE:
        _new( new_obj, 1 );
        new_obj->type = REND_OBJ_LINE;
        new_obj->base_colour = obj->base_colour;
        new_obj->black_edges = obj->black_edges;
        new_obj->rgn = obj->rgn;
        clip_3d_line( &(obj->obj.line), &(new_obj->obj.line), norm );
        break;
    case REND_OBJ_POLY:
        new_obj = rend_obj_new_poly();
        new_obj->base_colour = obj->base_colour;
        new_obj->black_edges = obj->black_edges;
        new_obj->rgn = obj->rgn;
        clip_3d_poly( &(obj->obj.poly), &(new_obj->obj.poly), norm );
        break;
    default:
        new_obj = NULL;
        break;
    }

    return( new_obj );
}

static point get_pt_from_array(
/*****************************/
    point   *array,
    int     pt_num
) {
    return( array[ pt_num ] );
}

static point * create_points_array(
/*********************************/
/* See rend_obj_create_sweep for details of how this works. */
/* This routine double the number of points. */
    pt_edge         *in_pts,
    int             num_pts,
    float           height,
    text_info *     text,
    bool            on_bottom       // is the text on bottom
) {
    point           *out_pts;
    vector          normal;
    int             curr_pt;

    _new( out_pts, 2 * num_pts );

    /* copy the original points into out_pts */
    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        out_pts[ curr_pt ] = in_pts[ curr_pt ].pt;
    }

    normal = calculate_normal_vector( num_pts, out_pts, (point(*)(void*,int))get_pt_from_array );

    /* add the new points to the points list */
    for (curr_pt = num_pts; curr_pt < 2*num_pts; curr_pt++) {
        out_pts[ curr_pt ].p[0] = in_pts[ curr_pt - num_pts ].pt.p[0] -
                                height * normal.v[0];
        out_pts[ curr_pt ].p[1] = in_pts[ curr_pt - num_pts ].pt.p[1] -
                                height * normal.v[1];
        out_pts[ curr_pt ].p[2] = in_pts[ curr_pt - num_pts ].pt.p[2] -
                                height * normal.v[2];
        out_pts[ curr_pt ].p[3] = 1.;
    }

    if( text != NULL ) {
        if( on_bottom ) {
            text->pt2 = text->pt1;
            text->pt1.p[0] = text->pt2.p[0] - height * normal.v[0];
            text->pt1.p[1] = text->pt2.p[1] - height * normal.v[1];
            text->pt1.p[2] = text->pt2.p[2] - height * normal.v[2];
            text->pt1.p[3] = 1.;
            text->centre.p[0] = text->centre.p[0] - height * normal.v[0];
            text->centre.p[1] = text->centre.p[1] - height * normal.v[1];
            text->centre.p[2] = text->centre.p[2] - height * normal.v[2];
            text->centre.p[3] = 1.;
        } else {
            text->pt2.p[0] = text->pt1.p[0] - height * normal.v[0];
            text->pt2.p[1] = text->pt1.p[1] - height * normal.v[1];
            text->pt2.p[2] = text->pt1.p[2] - height * normal.v[2];
            text->pt2.p[3] = 1.;
        }
    }

    return( out_pts );
}

/* these macros are used in the layout_faces fuction only */
#define _get_top_pt( pt_num, num_pts ) (pt_num) % (num_pts)
#define _get_bottom_pt( pt_num, num_pts) (pt_num) % (num_pts) + (num_pts)

static void layout_faces(
/***********************/
/* See rend_obj_create_sweep for how this routine works */
/* NOTE: This routine is sensitive to change. Make sure the side faces are */
/* set properly. */
    face_list *     list,
    rend_obj_add *  add
) {
    int             num_faces;
    int             curr_pt;
    int             curr_face;
    face            *faces;
    index_elt       *ind;
    int             num_pts;    // in the top face
    pt_edge         *edges;

    num_pts = add->num_pts;
    edges = add->pts;

    /* set up the face_list */
    num_faces = num_pts + 2;
    list->num_faces = num_faces;
    _new( list->faces, num_faces );
    faces = list->faces;

    /* add the top face */
    faces[0].num_pts = num_pts;
    faces[0].black = FALSE;
    faces[0].rgn_pt_iter = add->top_rgn_iter;
    _new( faces[0].index, faces[0].num_pts );
    ind = faces[0].index;                   // shorthand
    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        ind[ curr_pt ].pt_num = curr_pt;
        ind[ curr_pt ].hilight_edge = add->top_edges;
        ind[ curr_pt ].force_rgn_pt = edges[ curr_pt ].force_rgn_pt;
    }

    /* add the bottom face */
    faces[1].num_pts = num_pts;
    faces[1].black = FALSE;
    faces[1].rgn_pt_iter = add->bottom_rgn_iter;
    _new( faces[1].index, faces[1].num_pts );
    ind = faces[1].index;                   // shorthand
    for (curr_pt = 0; curr_pt < num_pts; curr_pt++) {
        ind[ curr_pt ].pt_num = (2*num_pts - 1) - curr_pt;
        ind[ curr_pt ].hilight_edge = add->bottom_edges;
        ind[ curr_pt ].force_rgn_pt =
                        edges[ (num_pts - 1) - curr_pt ].force_rgn_pt;
    }

    /* add the side faces */
    for (curr_face = 2; curr_face < num_faces; curr_face++) {
        curr_pt = curr_face - 2;
        faces[ curr_face ].num_pts = 4;     // side faces are rectangles
        faces[ curr_face ].black = edges[ curr_pt ].black_face;
        faces[ curr_face ].rgn_pt_iter = edges[ curr_pt ].face_rgn_iter;
        _new( faces[ curr_face ].index, faces[ curr_face ].num_pts );
        ind = faces[ curr_face  ].index;            // shorthand
        ind[0].pt_num = _get_top_pt( curr_pt, num_pts );
        ind[1].pt_num = _get_bottom_pt( curr_pt, num_pts );
        ind[2].pt_num = _get_bottom_pt( curr_pt+1, num_pts );
        ind[3].pt_num = _get_top_pt( curr_pt+1, num_pts );
        ind[0].hilight_edge = edges[ curr_pt ].edge;
        ind[1].hilight_edge = add->bottom_edges;
        ind[2].hilight_edge = edges[ curr_pt+1 ].edge;
        ind[3].hilight_edge = add->top_edges;
        ind[0].force_rgn_pt = FALSE;
        ind[1].force_rgn_pt = FALSE;

⌨️ 快捷键说明

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