/* * MODULE NAME: ex_angle.c * * FUNCTION: * This module contains code that draws extrusions with angled * joins ("angle join style"). It also inserts colors and normals * where necessary, if appropriate. * * HISTORY: * written by Linas Vepstas August/September 1991 * split into multiple compile units, Linas, October 1991 * added normal vectors Linas, October 1991 * "code complete" (that is, I'm done), Linas Vepstas, October 1991 * 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" /* ============================================================ */ /* * Algorithmic trivia: * * There is a slight bit of trivia which the super-duper exacto coder * needs to know about the code in this module. It is this: * * This module attempts to correctly treat contour normal vectors * by applying the inverse transpose of the 2D contour affine * transformation to the 2D contour normals. This is perfectly correct, * when applied to the "raw" join style. However, if the affine transform * has a strong rotational component, AND the join style is angle or * cut, then the normal vectors would continue to rotate as the * intersect point is extrapolated. * * The extrapolation of the inverse-transpose matrix to the intersection * point is not done. This would appear to be overkill for most * situations. The viewer might possibly detect an artifact of the * failure to do this correction IF all three of the following criteria * were met: * 1) The affine xform has a strong rotational component, * 2) The angle between two succesive segments is sharp (greater than 15 or * 30 degrees). * 3) The join style is angle or cut. * * However, I beleive that it is highly unlikely that the viewer will * detect any artifacts. The reason I beleive this is that a strong * rotational component will twist a segment so strongly that the more * visible artifact will be that a segment is composed of triangle strips. * As the user attempts to minimize the tesselation artifacts by shortening * segments, then the rotational component will decrease in proportion, * and the lighting artifact will fall away. * * To summarize, there is a slight inexactness in this code. The author * of the code beleives that this inexactness results in miniscule * errors in every situation. * * Linas Vepstas March 1993 */ /* ============================================================ */ void draw_angle_style_front_cap (int ncp, /* number of contour points */ gleDouble bi[3], /* biscetor */ gleDouble point_array[][3]) /* polyline */ { int j; #ifdef OPENGL_10 GLUtriangulatorObj *tobj; #endif /* OPENGL_10 */ if (bi[2] < 0.0) { VEC_SCALE (bi, -1.0, bi); } #ifdef GL_32 /* old-style gl handles concave polygons no problem, so the code is * simple. New-style gl is a lot more tricky. */ /* draw the end cap */ BGNPOLYGON (); N3F (bi); for (j=0; j 0.0) { VEC_SCALE (bi, -1.0, bi); } #ifdef GL_32 /* old-style gl handles concave polygons no problem, so the code is * simple. New-style gl is a lot more tricky. */ /* draw the end cap */ BGNPOLYGON (); N3F (bi); for (j=ncp-1; j>=0; j--) { V3F (point_array[j], j, BACK_CAP); } ENDPOLYGON (); #endif /* GL_32 */ #ifdef OPENGL_10 N3F (bi); tobj = gluNewTess (); gluTessCallback (tobj, GLU_BEGIN, glBegin); gluTessCallback (tobj, GLU_VERTEX, glVertex3dv); gluTessCallback (tobj, GLU_END, glEnd); gluBeginPolygon (tobj); for (j=ncp-1; j>=0; j--) { gluTessVertex (tobj, point_array[j], point_array[j]); } gluEndPolygon (tobj); gluDeleteTess (tobj); #endif /* OPENGL_10 */ } /* ============================================================ */ void extrusion_angle_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 len; gleDouble len_seg; gleDouble diff[3]; gleDouble bi_0[3], bi_1[3]; /* bisecting plane */ gleDouble bisector_0[3], bisector_1[3]; /* bisecting plane */ gleDouble end_point_0[3], end_point_1[3]; gleDouble origin[3], neg_z[3]; gleDouble yup[3]; /* alternate up vector */ gleDouble *front_loop, *back_loop; /* contours in 3D */ char * mem_anchor; double *norm_loop; double *front_norm, *back_norm, *tmp; /* contour normals in 3D */ int first_time; /* 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; /* ignore all segments of zero length */ i = 1; inext = i; FIND_NON_DEGENERATE_POINT (inext, npoints, len, diff, point_array); len_seg = len; /* store for later use */ /* get the bisecting plane */ bisecting_plane (bi_0, point_array[0], point_array[1], point_array[inext]); /* reflect the up vector in the bisecting plane */ VEC_REFLECT (yup, yup, bi_0); /* malloc the storage we'll need for relaying changed contours to the * drawing routines. */ mem_anchor = malloc (2 * 3 * ncp * sizeof(double) + 2 * 3 * ncp * sizeof(gleDouble)); front_loop = (gleDouble *) mem_anchor; back_loop = front_loop + 3 * ncp; front_norm = (double *) (back_loop + 3 * ncp); back_norm = front_norm + 3 * ncp; norm_loop = front_norm; /* may as well get the normals set up now */ if (cont_normal != NULL) { if (xform_array == NULL) { for (j=0; j