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 + -
显示快捷键?