/* * MODULE NAME: ex_cut_round.c * * FUNCTION: * This module contains code that draws extrusions with cut or round * join styles. The cut join style is a beveled edge. * The code also inserts colors and normals if appropriate. * * HISTORY: * written by Linas Vepstas August/September 1991 * split into multiple compile units, Linas, October 1991 * added normal vectors Linas, October 1991 * Fixed filleting problem, Linas February 1993 * Modified to handle round joins as well (based on common code), * Linas, March 1993 * work around OpenGL's lack of support for concave polys, June 1994 */ #include #include #include /* for the memcpy() subroutine */ #include #include "port.h" #include "gutil.h" #include "vvector.h" #include "tube_gc.h" #include "extrude.h" #include "intersect.h" #include "segment.h" #ifdef NONCONCAVE_CAPS /* ============================================================ */ /* * This subroutine draws a flat cap, to close off the cut ends * of the cut-style join. Because OpenGL doe not natively handle * concave polygons, this will cause some artifacts to appear on the * screen. */ void draw_cut_style_cap_callback (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards) { int i; if (face_color != NULL) C3F (face_color); if (frontwards) { /* if lighting is on, specify the endcap normal */ if (cut_vector != NULL) { /* if normal pointing in wrong direction, flip it. */ if (cut_vector[2] < 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } BGNPOLYGON(); for (i=0; i 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } /* the sense of the loop is reversed for backfacing culling */ BGNPOLYGON(); for (i=iloop-1; i>-1; i--) { V3F_D (cap[i], i, BACK_CAP); } ENDPOLYGON(); } } #else /* NONCONCAVE_CAPS */ /* ============================================================ */ /* * This subroutine draws a flat cap, to close off the cut ends * of the cut-style join. Properly handles concave endcaps. */ /* ARGSUSED4 */ static void draw_cut_style_cap_callback (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards) { int i; #ifdef OPENGL_10 GLUtriangulatorObj *tobj; tobj = gluNewTess (); gluTessCallback (tobj, GLU_BEGIN, glBegin); gluTessCallback (tobj, GLU_VERTEX, glVertex3dv); gluTessCallback (tobj, GLU_END, glEnd); #endif /* OPENGL_10 */ if (face_color != NULL) C3F (face_color); if (frontwards) { /* if lighting is on, specify the endcap normal */ if (cut_vector != NULL) { /* if normal pointing in wrong direction, flip it. */ if (cut_vector[2] < 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } #ifdef GL_32 BGNPOLYGON(); for (i=0; i 0.0) { VEC_SCALE (cut_vector, -1.0, cut_vector); } N3F_D (cut_vector); } /* the sense of the loop is reversed for backfacing culling */ #ifdef GL_32 BGNPOLYGON(); for (i=iloop-1; i>-1; i--) { V3F_D (cap[i], i, BACK_CAP); } ENDPOLYGON(); #endif /* GL_32 */ #ifdef OPENGL_10 gluBeginPolygon (tobj); for (i=iloop-1; i>-1; i--) { gluTessVertex (tobj, cap[i], cap[i]); } gluEndPolygon (tobj); #endif /* OPENGL_10 */ } #ifdef OPENGL_10 gluDeleteTess (tobj); #endif /* OPENGL_10 */ } #endif /* NONCONCAVE_ENDCAPS */ /* ============================================================ */ /* * This subroutine matchs the cap callback template, but is a no-op */ /* ARGSUSED */ void null_cap_callback (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards) {} /* ============================================================ */ /* * This little routine draws the little idd-biddy fillet triangle with * the right color, normal, etc. * * HACK ALERT -- there are two aspects to this routine/interface that * are "unfinished". * 1) the third point of the triangle should get a color thats * interpolated beween the front and back color. The interpolant * is not currently being computed. The error introduced by not * doing this should be tiny and/or non-exitant in almost all * expected uses of this code. * * 2) additional normal vectors should be supplied, and these should * be interpolated to fit. Currently, this is not being done. As * above, the expected error of not doing this should be tiny and/or * non-existant in almost all expected uses of this code. */ /* ARGSUSED6 */ static void draw_fillet_triangle_plain (gleDouble va[3], gleDouble vb[3], gleDouble vc[3], int face, float front_color[3], float back_color[3]) { if (front_color != NULL) C3F (front_color); BGNTMESH (-5, 0.0); if (face) { V3F (va, -1, FILLET); V3F (vb, -1, FILLET); } else { V3F (vb, -1, FILLET); V3F (va, -1, FILLET); } V3F (vc, -1, FILLET); ENDTMESH (); } /* ============================================================ */ /* * This little routine draws the little idd-biddy fillet triangle with * the right color, normal, etc. * * HACK ALERT -- there are two aspects to this routine/interface that * are "unfinished". * 1) the third point of the triangle should get a color thats * interpolated beween the front and back color. The interpolant * is not currently being computed. The error introduced by not * doing this should be tiny and/or non-exitant in almost all * expected uses of this code. * * 2) additional normal vectors should be supplied, and these should * be interpolated to fit. Currently, this is not being done. As * above, the expected error of not doing this should be tiny and/or * non-existant in almost all expected uses of this code. */ /* ARGSUSED5 */ static void draw_fillet_triangle_n_norms (gleDouble va[3], gleDouble vb[3], gleDouble vc[3], int face, float front_color[3], float back_color[3], double na[3], double nb[3]) { if (front_color != NULL) C3F (front_color); BGNTMESH (-5, 0.0); if (__TUBE_DRAW_FACET_NORMALS) { N3F_D (na); if (face) { V3F (va, -1, FILLET); V3F (vb, -1, FILLET); } else { V3F (vb, -1, FILLET); V3F (va, -1, FILLET); } V3F (vc, -1, FILLET); } else { if (face) { N3F_D (na); V3F (va, -1, FILLET); N3F_D (nb); V3F (vb, -1, FILLET); } else { N3F_D (nb); V3F (vb, -1, FILLET); N3F_D (na); V3F (va, -1, FILLET); N3F_D (nb); } V3F (vc, -1, FILLET); } ENDTMESH (); } /* ============================================================ */ static void draw_fillets_and_join_plain (int ncp, gleDouble trimmed_loop[][3], gleDouble untrimmed_loop[][3], int is_trimmed[], gleDouble bis_origin[3], gleDouble bis_vector[3], float front_color[3], float back_color[3], gleDouble cut_vector[3], int face, void ((*cap_callback) (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards))) { int istop; int icnt, icnt_prev, iloop; double *cap_loop; gleDouble sect[3]; gleDouble tmp_vec[3]; int save_style; int was_trimmed = FALSE; cap_loop = (double *) malloc ((ncp+3)*3*sizeof (double)); /* if the first point on the contour isn't trimmed, go ahead and * drop an edge down to the bisecting plane, (thus starting the * join). (Only need to do this for cut join, its bad if done for * round join). * * But if the first point is trimmed, keep going until one * is found that is not trimmed, and start join there. */ icnt = 0; iloop = 0; if (!is_trimmed[0]) { if (__TUBE_CUT_JOIN) { VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector); INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[0], tmp_vec); VEC_COPY ( (&cap_loop[3*iloop]), sect); iloop ++; } VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0])); iloop++; icnt_prev = icnt; icnt ++; } else { /* else, loop until an untrimmed point is found */ was_trimmed = TRUE; while (is_trimmed[icnt]) { icnt_prev = icnt; icnt ++; if (icnt >= ncp) { free (cap_loop); return; /* oops - everything was trimmed */ } } } /* Start walking around the end cap. Every time the end loop is * trimmed, we know we'll need to draw a fillet triangle. In * addition, after every pair of visibility changes, we draw a cap. */ if (__TUBE_CLOSE_CONTOUR) { istop = ncp; } else { istop = ncp-1; } /* save the join style, and disable a closed contour. * Need to do this so partial contours don't close up. */ save_style = gleGetJoinStyle (); gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED); for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) { /* There are four interesting cases for drawing caps and fillets: * 1) this & previous point were trimmed. Don't do anything, * advance counter. * 2) this point trimmed, previous not -- draw fillet, and * draw cap. * 3) this point not trimmed, previous one was -- compute * intersection point, draw fillet with it, and save * point for cap contour. * 4) this & previous point not trimmed -- save for endcap. */ /* Case 1 -- noop, just advance pointers */ if (is_trimmed[icnt_prev] && is_trimmed[icnt]) { } /* Case 2 -- Hah! first point! compute intersect & draw fillet! */ if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) { /* important note: the array "untrimmed" contains valid * untrimmed data ONLY when is_trim is TRUE. Otherwise, * only "trim" containes valid data */ /* compute intersection */ INNERSECT (sect, bis_origin, bis_vector, untrimmed_loop[icnt_prev], trimmed_loop[icnt]); /* Draw Fillet */ draw_fillet_triangle_plain (trimmed_loop[icnt_prev], trimmed_loop[icnt], sect, face, front_color, back_color); VEC_COPY ( (&cap_loop[3*iloop]), sect); iloop ++; VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); iloop++; } /* Case 3 -- add to collection of points */ if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) { VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); iloop++; } /* Case 4 -- Hah! last point! draw fillet & draw cap! */ if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) { was_trimmed = TRUE; /* important note: the array "untrimmed" contains valid * untrimmed data ONLY when is_trim is TRUE. Otherwise, * only "trim" containes valid data */ /* compute intersection */ INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[icnt_prev], untrimmed_loop[icnt]); /* Draw Fillet */ draw_fillet_triangle_plain (trimmed_loop[icnt_prev], trimmed_loop[icnt], sect, face, front_color, back_color); VEC_COPY ( (&cap_loop[3*iloop]), sect); iloop ++; /* draw cap */ if (iloop >= 3) (*cap_callback) (iloop, (gleDouble (*)[3]) cap_loop, front_color, cut_vector, bis_vector, NULL, face); /* reset cap counter */ iloop = 0; } } /* now, finish up in the same way that we started. If the last * point of the contour is visible, drop an edge to the bisecting * plane, thus finishing the join, and then, draw the join! */ icnt --; /* decrement to make up for loop exit condititons */ icnt += ncp; icnt %= ncp; if ((!is_trimmed[icnt]) && (iloop >= 2)) { VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector); INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[icnt], tmp_vec); VEC_COPY ( (&cap_loop[3*iloop]), sect); iloop ++; /* if nothing was ever trimmed, then we want to draw the * cap the way the user asked for it -- closed or not closed. * Therefore, reset the closure flag to its original state. */ if (!was_trimmed) { gleSetJoinStyle (save_style); } /* draw cap */ (*cap_callback) (iloop, (gleDouble (*)[3]) cap_loop, front_color, cut_vector, bis_vector, NULL, face); } /* rest to the saved style */ gleSetJoinStyle (save_style); free (cap_loop); } /* ============================================================ */ void draw_fillets_and_join_n_norms (int ncp, gleDouble trimmed_loop[][3], gleDouble untrimmed_loop[][3], int is_trimmed[], gleDouble bis_origin[3], gleDouble bis_vector[3], double normals[][3], float front_color[3], float back_color[3], gleDouble cut_vector[3], int face, void ((*cap_callback) (int iloop, double cap[][3], float face_color[3], gleDouble cut_vector[3], gleDouble bisect_vector[3], double norms[][3], int frontwards))) { int istop; int icnt, icnt_prev, iloop; double *cap_loop, *norm_loop; gleDouble sect[3]; gleDouble tmp_vec[3]; int save_style; int was_trimmed = FALSE; cap_loop = (double *) malloc ((ncp+3)*3*2*sizeof (double)); norm_loop = cap_loop + (ncp+3)*3; /* if the first point on the contour isn't trimmed, go ahead and * drop an edge down to the bisecting plane, (thus starting the * join). (Only need to do this for cut join, its bad if done for * round join). * * But if the first point is trimmed, keep going until one * is found that is not trimmed, and start join there. */ icnt = 0; iloop = 0; if (!is_trimmed[0]) { if (__TUBE_CUT_JOIN) { VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector); INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[0], tmp_vec); VEC_COPY ( (&cap_loop[3*iloop]), sect); VEC_COPY ( (&norm_loop[3*iloop]), normals[0]); iloop ++; } VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0])); VEC_COPY ( (&norm_loop[3*iloop]), normals[0]); iloop++; icnt_prev = icnt; icnt ++; } else { /* else, loop until an untrimmed point is found */ was_trimmed = TRUE; while (is_trimmed[icnt]) { icnt_prev = icnt; icnt ++; if (icnt >= ncp) { free (cap_loop); return; /* oops - everything was trimmed */ } } } /* Start walking around the end cap. Every time the end loop is * trimmed, we know we'll need to draw a fillet triangle. In * addition, after every pair of visibility changes, we draw a cap. */ if (__TUBE_CLOSE_CONTOUR) { istop = ncp; } else { istop = ncp-1; } /* save the join style, and disable a closed contour. * Need to do this so partial contours don't close up. */ save_style = gleGetJoinStyle (); gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED); for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) { /* There are four interesting cases for drawing caps and fillets: * 1) this & previous point were trimmed. Don't do anything, * advance counter. * 2) this point trimmed, previous not -- draw fillet, and * draw cap. * 3) this point not trimmed, previous one was -- compute * intersection point, draw fillet with it, and save * point for cap contour. * 4) this & previous point not trimmed -- save for endcap. */ /* Case 1 -- noop, just advance pointers */ if (is_trimmed[icnt_prev] && is_trimmed[icnt]) { } /* Case 2 -- Hah! first point! compute intersect & draw fillet! */ if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) { /* important note: the array "untrimmed" contains valid * untrimmed data ONLY when is_trim is TRUE. Otherwise, * only "trim" containes valid data */ /* compute intersection */ INNERSECT (sect, bis_origin, bis_vector, untrimmed_loop[icnt_prev], trimmed_loop[icnt]); /* Draw Fillet */ draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev], trimmed_loop[icnt], sect, face, front_color, back_color, normals[icnt_prev], normals[icnt]); VEC_COPY ( (&cap_loop[3*iloop]), sect); VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]); iloop ++; VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]); iloop++; } /* Case 3 -- add to collection of points */ if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) { VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt])); VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]); iloop++; } /* Case 4 -- Hah! last point! draw fillet & draw cap! */ if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) { was_trimmed = TRUE; /* important note: the array "untrimmed" contains valid * untrimmed data ONLY when is_trim is TRUE. Otherwise, * only "trim" containes valid data */ /* compute intersection */ INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[icnt_prev], untrimmed_loop[icnt]); /* Draw Fillet */ draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev], trimmed_loop[icnt], sect, face, front_color, back_color, normals[icnt_prev], normals[icnt]); VEC_COPY ( (&cap_loop[3*iloop]), sect); /* OK, maybe phong normals are wrong, but at least facet * normals will come out OK. */ if (__TUBE_DRAW_FACET_NORMALS) { VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]); } else { VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]); } iloop ++; /* draw cap */ if (iloop >= 3) (*cap_callback) (iloop, (gleDouble (*)[3]) cap_loop, front_color, cut_vector, bis_vector, (gleDouble (*)[3]) norm_loop, face); /* reset cap counter */ iloop = 0; } } /* now, finish up in the same way that we started. If the last * point of the contour is visible, drop an edge to the bisecting * plane, thus finishing the join, and then, draw the join! */ icnt --; /* decrement to make up for loop exit condititons */ icnt += ncp; icnt %= ncp; if ((!is_trimmed[icnt]) && (iloop >= 2)) { if (__TUBE_CUT_JOIN) { VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector); INNERSECT (sect, bis_origin, bis_vector, trimmed_loop[icnt], tmp_vec); VEC_COPY ( (&cap_loop[3*iloop]), sect); VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]); iloop ++; } /* if nothing was ever trimmed, then we want to draw the * cap the way the user asked for it -- closed or not closed. * Therefore, reset the closure flag to its original state. */ if (!was_trimmed) { gleSetJoinStyle (save_style); } /* draw cap */ (*cap_callback) (iloop, (gleDouble (*)[3]) cap_loop, front_color, cut_vector, bis_vector, (gleDouble (*)[3]) norm_loop, face); } /* rest to the saved style */ gleSetJoinStyle (save_style); free (cap_loop); } /* ============================================================ */ /* This routine draws "cut" style extrusions. */ void extrusion_round_or_cut_join (int ncp, /* number of contour points */ gleDouble contour[][2], /* 2D contour */ gleDouble cont_normal[][2],/* 2D normal vecs */ gleDouble up[3], /* up vector for contour */ int npoints, /* numpoints in poly-line */ gleDouble point_array[][3], /* polyline */ float color_array[][3], /* color of polyline */ gleDouble xform_array[][2][3]) /* 2D contour xforms */ { int i, j; int inext, inextnext; gleDouble m[4][4]; gleDouble tube_len, seg_len; gleDouble diff[3]; gleDouble bi_0[3], bi_1[3]; /* bisecting plane */ gleDouble bisector_0[3], bisector_1[3]; /* bisecting plane */ gleDouble cut_0[3], cut_1[3]; /* cutting planes */ gleDouble lcut_0[3], lcut_1[3]; /* cutting planes */ int valid_cut_0, valid_cut_1; /* flag -- cut vector is valid */ gleDouble end_point_0[3], end_point_1[3]; gleDouble torsion_point_0[3], torsion_point_1[3]; gleDouble isect_point[3]; gleDouble origin[3], neg_z[3]; gleDouble yup[3]; /* alternate up vector */ gleDouble *front_cap, *back_cap; /* arrays containing the end caps */ gleDouble *front_loop, *back_loop; /* arrays containing the tube ends */ double *front_norm, *back_norm; /* arrays containing normal vecs */ double *norm_loop, *tmp; /* normal vectors, cast into 3d from 2d */ int *front_is_trimmed, *back_is_trimmed; /* T or F */ float *front_color, *back_color; /* pointers to segment colors */ void ((*cap_callback) ()); /* function callback to draw cap */ void ((*tmp_cap_callback) ()); /* function callback to draw cap */ int join_style_is_cut; /* TRUE if join style is cut */ double dot; /* partial dot product */ char *mem_anchor; int first_time = TRUE; gleDouble *cut_vec; /* create a local, block scope copy of of the join style. * this will alleviate wasted cycles and register write-backs */ /* choose the right callback, depending on the choosen join style */ if (__TUBE_CUT_JOIN) { join_style_is_cut = TRUE; cap_callback = draw_cut_style_cap_callback; } else { join_style_is_cut = FALSE; cap_callback = draw_round_style_cap_callback; } /* By definition, the contour passed in has its up vector pointing in * the y direction */ if (up == NULL) { yup[0] = 0.0; yup[1] = 1.0; yup[2] = 0.0; } else { VEC_COPY (yup, up); } /* ========== "up" vector sanity check ========== */ (void) up_sanity_check (yup, npoints, point_array); /* the origin is at the origin */ origin [0] = 0.0; origin [1] = 0.0; origin [2] = 0.0; /* and neg_z is at neg z */ neg_z[0] = 0.0; neg_z[1] = 0.0; neg_z[2] = 1.0; /* malloc the data areas that we'll need to store the end-caps */ mem_anchor = malloc (4 * 3*ncp*sizeof(gleDouble) + 2 * 3*ncp*sizeof(double) + 2 * 1*ncp*sizeof(int)); front_norm = (double *) mem_anchor; back_norm = front_norm + 3*ncp; front_loop = (gleDouble *) (back_norm + 3*ncp); back_loop = front_loop + 3*ncp; front_cap = back_loop + 3*ncp; back_cap = front_cap + 3*ncp; front_is_trimmed = (int *) (back_cap + 3*ncp); back_is_trimmed = front_is_trimmed + ncp; /* ======================================= */ /* |-|-|-|-|-|-|-|-| SET UP FOR FIRST SEGMENT |-|-|-|-|-|-|-| */ /* ignore all segments of zero length */ i = 1; inext = i; FIND_NON_DEGENERATE_POINT (inext, npoints, seg_len, diff, point_array); tube_len = seg_len; /* store for later use */ /* may as well get the normals set up now */ if (cont_normal != NULL) { if (xform_array == NULL) { norm_loop = front_norm; back_norm = norm_loop; for (j=0; j 0.0)) { */ VEC_COPY ((&front_cap[3*j]), (&front_loop [3*j])); VEC_COPY ((&front_loop[3*j]), isect_point); front_is_trimmed[j] = TRUE; } else { front_is_trimmed[j] = FALSE; } /* if intersection is behind the end of the segment, * truncate to the end of the segment * Note that coding front_loop [3*j+2] = -tube_len; * doesn't work when twists are involved, */ if (front_loop[3*j+2] < -tube_len) { VEC_COPY( (&front_loop[3*j]), end_point_1); } /* --------------------------------------------------- */ /* The two end-points define a line. We did one endpoint * above. Now do the other.Intersect this line * against the clipping plane defined by the NEXT * tube segment. */ /* if this and the last tube are co-linear, don't cut the angle * if you do, a divide by zero will result. This and last tube * are co-linear when the cut vector is of zero length */ if (valid_cut_1 && join_style_is_cut) { INNERSECT (isect_point, /* isect point (returned) */ neg_z, /* point on intersecting plane */ lcut_1, /* normal vector to plane */ end_point_1, /* point on line */ end_point_0); /* another point on the line */ if (lcut_1[2] > 0.0) { VEC_SCALE (lcut_1, -1.0, lcut_1); } dot = lcut_1[0] * end_point_1[0]; dot += lcut_1[1] * end_point_1[1]; VEC_COPY ((&back_loop[3*j]), isect_point); } else { /* actual value of dot not interseting; need * only be positive so that if test below failes */ dot = 1.0; VEC_COPY ((&back_loop[3*j]), end_point_1); } INNERSECT (isect_point, /* intersection point (returned) */ neg_z, /* point on intersecting plane */ bisector_1, /* normal vector to plane */ torsion_point_0, /* point on line */ end_point_1); /* another point on the line */ /* cut out interior of intersecting tube */ /* ... but save the uncut version for drawing the endcaps */ /* ... note that cap contains valid data ONLY when is *_trimmed is TRUE. */ /* if ((dot <= 0.0) || (back_loop[3*j+2] < -tube_len)) { */ if ((dot <= 0.0) || (isect_point[2] > back_loop[3*j+2])) { VEC_COPY ((&back_cap[3*j]), (&back_loop [3*j])); VEC_COPY ((&back_loop[3*j]), isect_point); back_is_trimmed[j] = TRUE; } else { back_is_trimmed[j] = FALSE; } /* if intersection is behind the end of the segment, * truncate to the end of the segment * Note that coding back_loop [3*j+2] = 0.0; * doesn't work when twists are involved, */ if (back_loop[3*j+2] > 0.0) { VEC_COPY( (&back_loop[3*j]), end_point_0); } } /* --------- END OF TMESH GENERATION -------------- */ /* |||||||||||||||||| START SEGMENT DRAW |||||||||||||||||||| */ /* There are six different cases we can have for presence and/or * absecnce of colors and normals, and for interpretation of * normals. The blechy set of nested if statements below * branch to each of the six cases */ if (xform_array == NULL) { if (color_array == NULL) { if (cont_normal == NULL) { draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len); } else if (__TUBE_DRAW_FACET_NORMALS) { draw_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop, inext, seg_len); } else { draw_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop, inext, seg_len); } } else { if (cont_normal == NULL) { draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop, color_array[inext-1], color_array[inext], inext, seg_len); } else if (__TUBE_DRAW_FACET_NORMALS) { draw_segment_c_and_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop, color_array[inext-1], color_array[inext], inext, seg_len); } else { draw_segment_c_and_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop, color_array[inext-1], color_array[inext], inext, seg_len); } } } else { if (color_array == NULL) { if (cont_normal == NULL) { draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len); } else if (__TUBE_DRAW_FACET_NORMALS) { draw_binorm_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) front_norm, (gleVector *) back_norm, inext, seg_len); } else { draw_binorm_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) front_norm, (gleVector *) back_norm, inext, seg_len); } } else { if (cont_normal == NULL) { draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop, color_array[inext-1], color_array[inext], inext, seg_len); } else if (__TUBE_DRAW_FACET_NORMALS) { draw_binorm_segment_c_and_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) front_norm, (gleVector *) back_norm, color_array[inext-1], color_array[inext], inext, seg_len); } else { draw_binorm_segment_c_and_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) front_norm, (gleVector *) back_norm, color_array[inext-1], color_array[inext], inext, seg_len); } } } /* |||||||||||||||||| END SEGMENT DRAW |||||||||||||||||||| */ /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ /* if end caps are required, draw them. But don't draw any * but the very first and last caps */ if (first_time) { first_time = FALSE; tmp_cap_callback = cap_callback; cap_callback = null_cap_callback; if (__TUBE_DRAW_CAP) { if (color_array != NULL) C3F (color_array[inext-1]); draw_angle_style_front_cap (ncp, bisector_0, (gleDouble (*)[3]) front_loop); } } /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ /* $$$$$$$$$$$$$$$$ BEGIN -1, FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */ /* * Now, draw the fillet triangles, and the join-caps. */ if (color_array != NULL) { front_color = color_array[inext-1]; back_color = color_array[inext]; } else { front_color = NULL; back_color = NULL; } if (cont_normal == NULL) { /* the flag valid-cut is true if the cut vector has a valid * value (i.e. if a degenerate case has not occured). */ if (valid_cut_0) { cut_vec = lcut_0; } else { cut_vec = NULL; } draw_fillets_and_join_plain (ncp, (gleVector *) front_loop, (gleVector *) front_cap, front_is_trimmed, origin, bisector_0, front_color, back_color, cut_vec, TRUE, cap_callback); /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ if (inext == npoints-2) { if (__TUBE_DRAW_CAP) { if (color_array != NULL) C3F (color_array[inext]); draw_angle_style_back_cap (ncp, bisector_1, (gleDouble (*)[3]) back_loop); cap_callback = null_cap_callback; } } else { /* restore ability to draw cap */ cap_callback = tmp_cap_callback; } /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ /* the flag valid-cut is true if the cut vector has a valid * value (i.e. if a degenerate case has not occured). */ if (valid_cut_1) { cut_vec = lcut_1; } else { cut_vec = NULL; } draw_fillets_and_join_plain (ncp, (gleVector *) back_loop, (gleVector *) back_cap, back_is_trimmed, neg_z, bisector_1, back_color, front_color, cut_vec, FALSE, cap_callback); } else { /* the flag valid-cut is true if the cut vector has a valid * value (i.e. if a degenerate case has not occured). */ if (valid_cut_0) { cut_vec = lcut_0; } else { cut_vec = NULL; } draw_fillets_and_join_n_norms (ncp, (gleVector *) front_loop, (gleVector *) front_cap, front_is_trimmed, origin, bisector_0, (gleVector *) front_norm, front_color, back_color, cut_vec, TRUE, cap_callback); /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ if (inext == npoints-2) { if (__TUBE_DRAW_CAP) { if (color_array != NULL) C3F (color_array[inext]); draw_angle_style_back_cap (ncp, bisector_1, (gleDouble (*)[3]) back_loop); cap_callback = null_cap_callback; } } else { /* restore ability to draw cap */ cap_callback = tmp_cap_callback; } /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */ /* the flag valid-cut is true if the cut vector has a valid * value (i.e. if a degenerate case has not occured). */ if (valid_cut_1) { cut_vec = lcut_1; } else { cut_vec = NULL; } draw_fillets_and_join_n_norms (ncp, (gleVector *) back_loop, (gleVector *) back_cap, back_is_trimmed, neg_z, bisector_1, (gleVector *) back_norm, back_color, front_color, cut_vec, FALSE, cap_callback); } /* $$$$$$$$$$$$$$$$ END FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */ /* pop this matrix, do the next set */ POPMATRIX (); /* slosh stuff over to next vertex */ tmp = front_norm; front_norm = back_norm; back_norm = tmp; tube_len = seg_len; i = inext; inext = inextnext; VEC_COPY (bi_0, bi_1); VEC_COPY (cut_0, cut_1); valid_cut_0 = valid_cut_1; /* reflect the up vector in the bisecting plane */ VEC_REFLECT (yup, yup, bi_0); } /* |-|-|-|-|-|-|-|-| END LOOP OVER SEGMENTS |-|-|-|-|-|-|-| */ free (mem_anchor); } /* =================== END OF FILE =============================== */