1 /*
2  * MODULE NAME: ex_raw.c
3  *
4  * FUNCTION:
5  * This module contains code that draws extrusions with square
6  * ("raw join style") end styles.  It also inserts colors and normals
7  * where necessary, if appropriate.
8  *
9  * HISTORY:
10  * written by Linas Vepstas August/September 1991
11  * split into multiple compile units, Linas, October 1991
12  * added normal vectors Linas, October 1991
13  * "code complete" (that is, I'm done), Linas Vepstas, October 1991
14  * work around OpenGL's lack of support for concave polys, June 1994
15  *
16  * Copyright (C) 1991,1994,2003 Linas Vepstas <linas@linas.org>
17  */
18 
19 
20 #include <stdlib.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include <string.h>	/* for the memcpy() subroutine */
24 #include <stdio.h>      /* to get stderr defined */
25 
26 #include "gle.h"
27 
28 #include "port.h"
29 #include "vvector.h"
30 #include "tube_gc.h"
31 #include "extrude.h"
32 #include "intersect.h"
33 #include "segment.h"
34 
35 /* ============================================================ */
36 #ifndef COLOR_SIGNATURE
37 /*
38  * The following routine is, in principle, very simple:
39  * all that it does is normalize the up vector, and makes
40  * sure that it is perpendicular to the initial polyline segment.
41  *
42  * In fact, this routine gets awfully complicated because:
43  * a) the first few segements of the polyline might be degenerate,
44  * b) up vecotr may be parallel to first few segments of polyline,
45  * c) etc.
46  *
47  */
48 
up_sanity_check(gleDouble up[3],int npoints,gleDouble point_array[][3])49 void up_sanity_check (gleDouble up[3],	/* up vector for contour */
50                       int npoints,		/* numpoints in poly-line */
51                       gleDouble point_array[][3])	/* polyline */
52 {
53    int i;
54    double len;
55    double diff[3];
56 
57    /* now, right off the bat, we should make sure that the up vector
58     * is in fact perpendicular to the polyline direction */
59    VEC_DIFF (diff, point_array[1], point_array[0]);
60    VEC_LENGTH (len, diff);
61    if (len == 0.0) {
62       /* This error message should go through an "official" error interface */
63 #ifndef WIN32
64       /* Win32 GUI programs do not have a valid error stream; and so
65        * although they compile, they will crash when run. */
66       fprintf (stderr, "Extrusion: Warning: initial segment zero length \n");
67 #endif /* WIN32 */
68 
69       /* loop till we find something that ain't of zero length */
70       for (i=1; i<npoints-2; i++) {
71          VEC_DIFF (diff, point_array[i+1], point_array[i]);
72          VEC_LENGTH (len, diff);
73          if (len != 0.0) break;
74       }
75    }
76 
77    /* normalize diff to be of unit length */
78    len = 1.0 / len;
79    VEC_SCALE (diff, len, diff);
80 
81    /* we want to take only perpendicular component of up w.r.t. the
82     * initial segment */
83    VEC_PERP (up, up, diff);
84 
85    VEC_LENGTH (len, up);
86    if (len == 0.0) {
87       /* This error message should go through an "official" error interface */
88 #ifndef WIN32
89       /* Win32 GUI programs do not have a valid error stream; and so
90        * although they compile, they will crash when run. */
91       fprintf (stderr, "Extrusion: Warning: "
92                "contour up vector parallel to tubing direction \n");
93 #endif /* WIN32 */
94 
95       /* do like the error message says ... */
96       VEC_COPY (up, diff);
97    }
98 
99 }
100 
101 /* ============================================================ */
102 /*
103  * This routine does what it says: It draws the end-caps for the
104  * "raw" join style.
105  */
106 
draw_raw_style_end_cap(int ncp,gleDouble contour[][2],gleDouble zval,int frontwards)107 void draw_raw_style_end_cap (int ncp,		/* number of contour points */
108                              gleDouble contour[][2],	/* 2D contour */
109                              gleDouble zval,		/* where to draw cap */
110                              int frontwards)	/* front or back cap */
111 {
112    int j;
113 
114 #ifdef GL_32
115    gleDouble point[3];
116 #endif /* GL_32 */
117 
118 #ifdef OPENGL_10
119    GLUtriangulatorObj *tobj;
120    double *pts;
121 #endif /* OPENGL_10 */
122 
123 
124 #ifdef GL_32
125    /* Old-style gl handles concave polygons no problem, so the code is
126     * simple.  New-style gl is a lot more tricky. */
127    point [2] = zval;
128    BGNPOLYGON ();
129       /* draw the loop counter clockwise for the front cap */
130       if (frontwards) {
131          for (j=0; j<ncp; j++) {
132             point [0] = contour[j][0];
133             point [1] = contour[j][1];
134             V3F (point, j, FRONT_CAP);
135          }
136 
137       } else {
138          /* the sense of the loop is reversed for backfacing culling */
139          for (j=ncp-1; j>-1; j--) {
140             point [0] = contour[j][0];
141             point [1] = contour[j][1];
142             V3F (point, j, BACK_CAP);
143          }
144       }
145    ENDPOLYGON ();
146 #endif /* GL_32 */
147 
148 #ifdef OPENGL_10
149    /* malloc the @#$%^&* array that OpenGL wants ! */
150    pts = (double *) malloc (3*ncp*sizeof(double));
151    tobj = gluNewTess ();
152    gluTessCallback (tobj, GLU_BEGIN, glBegin);
153    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
154    gluTessCallback (tobj, GLU_END, glEnd);
155    gluBeginPolygon (tobj);
156 
157       /* draw the loop counter clockwise for the front cap */
158       if (frontwards) {
159          for (j=0; j<ncp; j++) {
160             pts [3*j] = contour[j][0];
161             pts [3*j+1] = contour[j][1];
162             pts [3*j+2] = zval;
163             gluTessVertex (tobj, &pts[3*j], &pts[3*j]);
164          }
165 
166       } else {
167          /* the sense of the loop is reversed for backfacing culling */
168          for (j=ncp-1; j>-1; j--) {
169             pts [3*j] = contour[j][0];
170             pts [3*j+1] = contour[j][1];
171             pts [3*j+2] = zval;
172             gluTessVertex (tobj, &pts[3*j], &pts[3*j]);
173          }
174       }
175 
176    gluEndPolygon (tobj);
177    free (pts);
178    gluDeleteTess (tobj);
179 #endif /* OPENGL_10 */
180 }
181 
182 #endif /* COLOR_SIGNATURE */
183 /* ============================================================ */
184 /* This routine does what it says: It draws a counter-clockwise cap
185  * from a 3D contour loop list
186  */
187 
188 static void
draw_front_contour_cap(int ncp,gleDouble contour[][3])189 draw_front_contour_cap (int ncp,	/* number of contour points */
190                              gleDouble contour[][3])	/* 3D contour */
191 {
192    int j;
193 
194 #ifdef OPENGL_10
195    GLUtriangulatorObj *tobj;
196 #endif /* OPENGL_10 */
197 
198 #ifdef GL_32
199    /* old-style gl handles concave polygons no problem, so the code is
200     * simple.  New-style gl is a lot more tricky. */
201    /* draw the end cap */
202    BGNPOLYGON ();
203 
204    for (j=0; j<ncp; j++) {
205       V3F (contour[j], j, FRONT_CAP);
206    }
207    ENDPOLYGON ();
208 #endif /* GL_32 */
209 
210 #ifdef OPENGL_10
211    tobj = gluNewTess ();
212    gluTessCallback (tobj, GLU_BEGIN, glBegin);
213    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
214    gluTessCallback (tobj, GLU_END, glEnd);
215    gluBeginPolygon (tobj);
216 
217    for (j=0; j<ncp; j++) {
218       gluTessVertex (tobj, contour[j], contour[j]);
219    }
220    gluEndPolygon (tobj);
221    gluDeleteTess (tobj);
222 #endif /* OPENGL_10 */
223 }
224 
225 
226 /* ============================================================ */
227 /* This routine does what it says: It draws a clockwise cap
228  * from a 3D contour loop list
229  */
230 
231 static void
draw_back_contour_cap(int ncp,gleDouble contour[][3])232 draw_back_contour_cap (int ncp,	/* number of contour points */
233                              gleDouble contour[][3])	/* 3D contour */
234 {
235    int j;
236 
237 #ifdef OPENGL_10
238    GLUtriangulatorObj *tobj;
239 #endif /* OPENGL_10 */
240 
241 #ifdef GL_32
242    /* old-style gl handles concave polygons no problem, so the code is
243     * simple.  New-style gl is a lot more tricky. */
244 
245    /* draw the end cap */
246    /* draw the loop clockwise for the back cap */
247    /* the sense of the loop is reversed for backfacing culling */
248    BGNPOLYGON ();
249 
250    for (j=ncp-1; j>-1; j--) {
251       V3F (contour[j], j, BACK_CAP);
252    }
253    ENDPOLYGON ();
254 #endif /* GL_32 */
255 
256 #ifdef OPENGL_10
257    tobj = gluNewTess ();
258    gluTessCallback (tobj, GLU_BEGIN, glBegin);
259    gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
260    gluTessCallback (tobj, GLU_END, glEnd);
261    gluBeginPolygon (tobj);
262 
263    /* draw the end cap */
264    /* draw the loop clockwise for the back cap */
265    /* the sense of the loop is reversed for backfacing culling */
266    for (j=ncp-1; j>-1; j--) {
267       gluTessVertex (tobj, contour[j], contour[j]);
268    }
269    gluEndPolygon (tobj);
270    gluDeleteTess (tobj);
271 #endif /* OPENGL_10 */
272 }
273 
274 /* ============================================================ */
275 /* This routine draws a segment of raw-join-style tubing.
276  * Essentially, we assume that the proper transformations have already
277  * been performed to properly orient the tube segment -- our only task
278  * left is to render */
279 /* PLAIN - NO COLOR, NO NORMAL */
280 
281 static void
draw_raw_segment_plain(int ncp,gleDouble contour[][2],int inext,gleDouble len)282 draw_raw_segment_plain (int ncp,		/* number of contour points */
283                              gleDouble contour[][2],	/* 2D contour */
284                              int inext,
285                              gleDouble len)
286 
287 {
288    int j;
289    double point[3];
290 
291    /* draw the tube segment */
292    BGNTMESH (inext, len);
293    for (j=0; j<ncp; j++) {
294       point [0] = contour[j][0];
295       point [1] = contour[j][1];
296       point [2] = 0.0;
297       V3F (point, j, FRONT);
298 
299       point [2] = - len;
300       V3F (point, j, BACK);
301    }
302 
303    if (__TUBE_CLOSE_CONTOUR) {
304       /* connect back up to first point of contour */
305       point [0] = contour[0][0];
306       point [1] = contour[0][1];
307       point [2] = 0.0;
308       V3F (point, 0, FRONT);
309 
310       point [2] = - len;
311       V3F (point, 0, BACK);
312    }
313 
314    ENDTMESH ();
315 
316    /* draw the endcaps, if the join style calls for it */
317    if (__TUBE_DRAW_CAP) {
318 
319       /* draw the front cap */
320       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
321 
322       /* draw the back cap */
323       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
324    }
325 }
326 
327 /* ============================================================ */
328 /* This routine draws a segment of raw-join-style tubing.
329  * Essentially, we assume that the proper transformations have already
330  * been performed to properly orient the tube segment -- our only task
331  * left is to render */
332 /* COLOR -- DRAW ONLY COLOR */
333 
334 static void
draw_raw_segment_color(int ncp,gleDouble contour[][2],gleColor color_array[],int inext,gleDouble len)335 draw_raw_segment_color (int ncp,		/* number of contour points */
336                              gleDouble contour[][2],	/* 2D contour */
337                              gleColor color_array[],	/* color of polyline */
338                              int inext,
339                              gleDouble len)
340 
341 {
342    int j;
343    double point[3];
344 
345    /* draw the tube segment */
346    BGNTMESH (inext, len);
347    for (j=0; j<ncp; j++) {
348       point [0] = contour[j][0];
349       point [1] = contour[j][1];
350       point [2] = 0.0;
351       C3F (color_array[inext-1]);
352       V3F (point, j, FRONT);
353 
354       point [2] = - len;
355       C3F (color_array[inext]);
356       V3F (point, j, BACK);
357    }
358 
359    if (__TUBE_CLOSE_CONTOUR) {
360       /* connect back up to first point of contour */
361       point [0] = contour[0][0];
362       point [1] = contour[0][1];
363       point [2] = 0.0;
364 
365       C3F (color_array[inext-1]);
366       V3F (point, 0, FRONT);
367 
368       point [2] = - len;
369       C3F (color_array[inext]);
370       V3F (point, 0, BACK);
371    }
372 
373    ENDTMESH ();
374 
375    /* draw the endcaps, if the join style calls for it */
376    if (__TUBE_DRAW_CAP) {
377 
378       /* draw the front cap */
379       C3F (color_array[inext-1]);
380       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
381 
382       /* draw the back cap */
383       C3F (color_array[inext]);
384       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
385    }
386 
387 }
388 
389 /* ============================================================ */
390 /* This routine draws a segment of raw-join-style tubing.
391  * Essentially, we assume that the proper transformations have already
392  * been performed to properly orient the tube segment -- our only task
393  * left is to render */
394 /* EDGE_N -- DRAW ONLY EDGE NORMALS */
395 
396 static void
draw_raw_segment_edge_n(int ncp,gleDouble contour[][2],gleDouble cont_normal[][2],int inext,gleDouble len)397 draw_raw_segment_edge_n (int ncp,	/* number of contour points */
398                              gleDouble contour[][2],	/* 2D contour */
399                              gleDouble cont_normal[][2],/* 2D normal vecs */
400                              int inext,
401                              gleDouble len)
402 
403 {
404    int j;
405    double point[3];
406    double norm[3];
407 
408    /* draw the tube segment */
409    norm [2] = 0.0;
410    BGNTMESH (inext, len);
411    for (j=0; j<ncp; j++) {
412       norm [0] = cont_normal[j][0];
413       norm [1] = cont_normal[j][1];
414       N3F (norm);
415 
416       point [0] = contour[j][0];
417       point [1] = contour[j][1];
418       point [2] = 0.0;
419       V3F (point, j, FRONT);
420 
421       point [2] = - len;
422       V3F (point, j, BACK);
423    }
424 
425    if (__TUBE_CLOSE_CONTOUR) {
426       /* connect back up to first point of contour */
427       norm [0] = cont_normal[0][0];
428       norm [1] = cont_normal[0][1];
429       norm [2] = 0.0;
430       N3F (norm);
431 
432       point [0] = contour[0][0];
433       point [1] = contour[0][1];
434       point [2] = 0.0;
435       V3F (point, 0, FRONT);
436 
437       point [2] = - len;
438       V3F (point, 0, BACK);
439    }
440 
441    ENDTMESH ();
442 
443    /* draw the endcaps, if the join style calls for it */
444    if (__TUBE_DRAW_CAP) {
445 
446       /* draw the front cap */
447       norm [0] = norm [1] = 0.0;
448       norm [2] = 1.0;
449       N3F (norm);
450       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
451 
452       /* draw the back cap */
453       norm [2] = -1.0;
454       N3F (norm);
455       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
456    }
457 
458 }
459 
460 /* ============================================================ */
461 /* This routine draws a segment of raw-join-style tubing.
462  * Essentially, we assume that the proper transformations have already
463  * been performed to properly orient the tube segment -- our only task
464  * left is to render */
465 /* C_AND_EDGE_N -- DRAW EDGE NORMALS AND COLORS */
466 
467 static void
draw_raw_segment_c_and_edge_n(int ncp,gleDouble contour[][2],gleColor color_array[],gleDouble cont_normal[][2],int inext,gleDouble len)468 draw_raw_segment_c_and_edge_n (int ncp,	/* number of contour points */
469                              gleDouble contour[][2],	/* 2D contour */
470                              gleColor color_array[],	/* color of polyline */
471                              gleDouble cont_normal[][2],/* 2D normal vecs */
472                              int inext,
473                              gleDouble len)
474 
475 {
476    int j;
477    double point[3];
478    double norm[3];
479 
480    /* draw the tube segment */
481    norm [2] = 0.0;
482    BGNTMESH (inext, len);
483    for (j=0; j<ncp; j++) {
484       C3F (color_array[inext-1]);
485 
486       norm [0] = cont_normal[j][0];
487       norm [1] = cont_normal[j][1];
488       N3F (norm);
489 
490       point [0] = contour[j][0];
491       point [1] = contour[j][1];
492       point [2] = 0.0;
493       V3F (point, j, FRONT);
494 
495       C3F (color_array[inext]);
496       N3F (norm);
497 
498       point [2] = - len;
499       V3F (point, j, BACK);
500    }
501 
502    if (__TUBE_CLOSE_CONTOUR) {
503       /* connect back up to first point of contour */
504       C3F (color_array[inext-1]);
505 
506       norm [0] = cont_normal[0][0];
507       norm [1] = cont_normal[0][1];
508       N3F (norm);
509 
510       point [0] = contour[0][0];
511       point [1] = contour[0][1];
512       point [2] = 0.0;
513       V3F (point, 0, FRONT);
514 
515 
516       C3F (color_array[inext]);
517       norm [0] = cont_normal[0][0];
518       norm [1] = cont_normal[0][1];
519       N3F (norm);
520 
521       point [2] = - len;
522       V3F (point, 0, BACK);
523    }
524 
525    ENDTMESH ();
526 
527    /* draw the endcaps, if the join style calls for it */
528    if (__TUBE_DRAW_CAP) {
529 
530       /* draw the front cap */
531       C3F (color_array[inext-1]);
532       norm [0] = norm [1] = 0.0;
533       norm [2] = 1.0;
534       N3F (norm);
535       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
536 
537       /* draw the back cap */
538       C3F (color_array[inext]);
539       norm [2] = -1.0;
540       N3F (norm);
541       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
542    }
543 
544 }
545 
546 /* ============================================================ */
547 /* This routine draws a segment of raw-join-style tubing.
548  * Essentially, we assume that the proper transformations have already
549  * been performed to properly orient the tube segment -- our only task
550  * left is to render */
551 /* FACET_N -- DRAW ONLY FACET NORMALS */
552 
553 static void
draw_raw_segment_facet_n(int ncp,gleDouble contour[][2],gleDouble cont_normal[][2],int inext,gleDouble len)554 draw_raw_segment_facet_n (int ncp,	/* number of contour points */
555                              gleDouble contour[][2],	/* 2D contour */
556                              gleDouble cont_normal[][2],/* 2D normal vecs */
557                              int inext,
558                              gleDouble len)
559 
560 {
561    int j;
562    double point[3];
563    double norm[3];
564 
565    /* draw the tube segment */
566    norm [2] = 0.0;
567    BGNTMESH (inext, len);
568    for (j=0; j<ncp-1; j++) {
569       /* facet normals require one normal per four vertices */
570       norm [0] = cont_normal[j][0];
571       norm [1] = cont_normal[j][1];
572       N3F (norm);
573 
574       point [0] = contour[j][0];
575       point [1] = contour[j][1];
576       point [2] = 0.0;
577       V3F (point, j, FRONT);
578 
579       point [2] = - len;
580       V3F (point, j, BACK);
581 
582       point [0] = contour[j+1][0];
583       point [1] = contour[j+1][1];
584       point [2] = 0.0;
585       V3F (point, j+1, FRONT);
586 
587       point [2] = - len;
588       V3F (point, j+1, BACK);
589    }
590 
591    if (__TUBE_CLOSE_CONTOUR) {
592       /* connect back up to first point of contour */
593       norm [0] = cont_normal[ncp-1][0];
594       norm [1] = cont_normal[ncp-1][1];
595       N3F (norm);
596 
597       point [0] = contour[ncp-1][0];
598       point [1] = contour[ncp-1][1];
599       point [2] = 0.0;
600       V3F (point, ncp-1, FRONT);
601 
602       point [2] = - len;
603       V3F (point, ncp-1, BACK);
604 
605       point [0] = contour[0][0];
606       point [1] = contour[0][1];
607       point [2] = 0.0;
608       V3F (point, 0, FRONT);
609 
610       point [2] = - len;
611       V3F (point, 0, BACK);
612    }
613 
614    ENDTMESH ();
615 
616    /* draw the endcaps, if the join style calls for it */
617    if (__TUBE_DRAW_CAP) {
618 
619       /* draw the front cap */
620       norm [0] = norm [1] = 0.0;
621       norm [2] = 1.0;
622       N3F (norm);
623       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
624 
625       /* draw the back cap */
626       norm [2] = -1.0;
627       N3F (norm);
628       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
629    }
630 
631 }
632 
633 /* ============================================================ */
634 /* This routine draws a segment of raw-join-style tubing.
635  * Essentially, we assume that the proper transformations have already
636  * been performed to properly orient the tube segment -- our only task
637  * left is to render */
638 /* C_AND_FACET_N -- DRAW FACET NORMALS AND COLORS */
639 
640 static void
draw_raw_segment_c_and_facet_n(int ncp,gleDouble contour[][2],gleColor color_array[],gleDouble cont_normal[][2],int inext,gleDouble len)641 draw_raw_segment_c_and_facet_n (int ncp,	/* number of contour points */
642                              gleDouble contour[][2],	/* 2D contour */
643                              gleColor color_array[],	/* color of polyline */
644                              gleDouble cont_normal[][2],/* 2D normal vecs */
645                              int inext,
646                              gleDouble len)
647 
648 {
649    int j;
650    double point[3];
651    double norm[3];
652 
653    /* draw the tube segment */
654    norm [2] = 0.0;
655    BGNTMESH (inext, len);
656    for (j=0; j<ncp-1; j++) {
657       /* facet normals require one normal per four vertices;
658        * However, we have to respecify normal each time at each vertex
659        * so that the lighting equation gets triggered.  (V3F does NOT
660        * automatically trigger the lighting equations -- it only
661        * triggers when there is a local light) */
662 
663       C3F (color_array[inext-1]);
664 
665       norm [0] = cont_normal[j][0];
666       norm [1] = cont_normal[j][1];
667       N3F (norm);
668 
669       point [0] = contour[j][0];
670       point [1] = contour[j][1];
671       point [2] = 0.0;
672       V3F (point, j, FRONT);
673 
674       C3F (color_array[inext]);
675       N3F (norm);
676       point [2] = - len;
677       V3F (point, j, BACK);
678 
679 
680       C3F (color_array[inext-1]);
681       N3F (norm);
682 
683       point [0] = contour[j+1][0];
684       point [1] = contour[j+1][1];
685       point [2] = 0.0;
686       V3F (point, j+1, FRONT);
687 
688       C3F (color_array[inext]);
689       N3F (norm);
690       point [2] = - len;
691       V3F (point, j+1, BACK);
692    }
693 
694    if (__TUBE_CLOSE_CONTOUR) {
695       /* connect back up to first point of contour */
696       point [0] = contour[ncp-1][0];
697       point [1] = contour[ncp-1][1];
698       point [2] = 0.0;
699       C3F (color_array[inext-1]);
700 
701       norm [0] = cont_normal[ncp-1][0];
702       norm [1] = cont_normal[ncp-1][1];
703       N3F (norm);
704       V3F (point, ncp-1, FRONT);
705 
706       C3F (color_array[inext]);
707       N3F (norm);
708 
709       point [2] = - len;
710       V3F (point, ncp-1, BACK);
711 
712       C3F (color_array[inext-1]);
713 
714       norm [0] = cont_normal[0][0];
715       norm [1] = cont_normal[0][1];
716       N3F (norm);
717 
718       point [0] = contour[0][0];
719       point [1] = contour[0][1];
720       point [2] = 0.0;
721       V3F (point, 0, FRONT);
722 
723       C3F (color_array[inext]);
724       N3F (norm);
725 
726       point [2] = - len;
727       V3F (point, 0, BACK);
728    }
729 
730    ENDTMESH ();
731 
732    /* draw the endcaps, if the join style calls for it */
733    if (__TUBE_DRAW_CAP) {
734 
735       /* draw the front cap */
736       C3F (color_array[inext-1]);
737       norm [0] = norm [1] = 0.0;
738       norm [2] = 1.0;
739       N3F (norm);
740       draw_raw_style_end_cap (ncp, contour, 0.0, TRUE);
741 
742       /* draw the back cap */
743       C3F (color_array[inext]);
744       norm [2] = -1.0;
745       N3F (norm);
746       draw_raw_style_end_cap (ncp, contour, -len, FALSE);
747    }
748 
749 }
750 
751 /* ============================================================ */
752 /* This routine draws "raw" style extrusions.  By "raw" style, it is
753  * meant extrusions with square ends: ends that are cut at 90 degrees to
754  * the length of the extrusion.  End caps are NOT drawn, unless the end cap
755  * style is indicated.
756  */
757 
extrusion_raw_join(int ncp,gleDouble contour[][2],gleDouble cont_normal[][2],gleDouble up[3],int npoints,gleDouble point_array[][3],gleColor color_array[],gleDouble xform_array[][2][3])758 void extrusion_raw_join (int ncp,		/* number of contour points */
759                          gleDouble contour[][2],	/* 2D contour */
760                          gleDouble cont_normal[][2],/* 2D contour normal vecs */
761                          gleDouble up[3],	/* up vector for contour */
762                          int npoints,		/* numpoints in poly-line */
763                          gleDouble point_array[][3],	/* polyline */
764                          gleColor color_array[],	/* color of polyline */
765                          gleDouble xform_array[][2][3])   /* 2D contour xforms */
766 {
767    int i, j;
768    int inext;
769    gleDouble m[4][4];
770    gleDouble len;
771    gleDouble diff[3];
772    gleDouble bi_0[3];		/* bisecting plane */
773    gleDouble yup[3];		/* alternate up vector */
774    gleDouble nrmv[3];
775    short no_norm, no_cols, no_xform;     /*booleans */
776    char *mem_anchor = 0x0;
777    gleDouble *front_loop=0x0, *back_loop=0x0;  /* countour loops */
778    gleDouble *front_norm=0x0, *back_norm=0x0;  /* countour loops */
779    gleDouble *tmp;
780 
781    nrmv[0] = nrmv[1] = 0.0;   /* used for drawing end caps */
782    /* use some local variables for needed booleans */
783    no_norm = (cont_normal == NULL);
784    no_cols = (color_array == NULL);
785    no_xform = (xform_array == NULL);
786 
787    /* alloc loop arrays if needed */
788    if (! no_xform) {
789       mem_anchor = malloc (4 * ncp * 3 * sizeof(gleDouble));
790       front_loop = (gleDouble *) mem_anchor;
791       back_loop = front_loop + 3*ncp;
792       front_norm = back_loop + 3*ncp;
793       back_norm = front_norm + 3*ncp;
794    }
795 
796    /* By definition, the contour passed in has its up vector pointing in
797     * the y direction */
798    if (up == NULL) {
799       yup[0] = 0.0;
800       yup[1] = 1.0;
801       yup[2] = 0.0;
802    } else {
803       VEC_COPY (yup, up);
804    }
805 
806    /* ========== "up" vector sanity check ========== */
807    (void) up_sanity_check (yup, npoints, point_array);
808 
809    /* ignore all segments of zero length */
810    i = 1;
811    inext = i;
812    FIND_NON_DEGENERATE_POINT (inext, npoints, len, diff, point_array);
813 
814    /* first time through, get the loops */
815    if (! no_xform) {
816       for (j=0; j<ncp; j++) {
817             MAT_DOT_VEC_2X3 ((&front_loop[3*j]),
818                              xform_array[inext-1], contour[j]);
819             front_loop[3*j+2] = 0.0;
820       }
821       if (!no_norm) {
822          for (j=0; j<ncp; j++) {
823             NORM_XFORM_2X2 ( (&front_norm[3*j]),
824                              xform_array[inext-1],
825                              cont_normal [j]);
826             front_norm[3*j+2] = 0.0;
827             back_norm[3*j+2] = 0.0;
828          }
829       }
830    }
831 
832    /* draw tubing, not doing the first segment */
833    while (inext<npoints-1) {
834 
835       /* get the two bisecting planes */
836       bisecting_plane (bi_0, point_array[i-1],
837                              point_array[i],
838                              point_array[inext]);
839 
840       /* reflect the up vector in the bisecting plane */
841       VEC_REFLECT (yup, yup, bi_0);
842 
843       /* rotate so that z-axis points down v2-v1 axis,
844        * and so that origen is at v1 */
845       uviewpoint (m, point_array[i], point_array[inext], yup);
846       PUSHMATRIX ();
847       MULTMATRIX (m);
848 
849       /* There are six different cases we can have for presence and/or
850        * absecnce of colors and normals, and for interpretation of
851        * normals. The blechy set of nested if statements below
852        * branch to each of the six cases */
853       if (no_xform) {
854          if (no_cols) {
855             if (no_norm) {
856                draw_raw_segment_plain (ncp, contour, inext, len);
857             } else
858             if (__TUBE_DRAW_FACET_NORMALS) {
859                draw_raw_segment_facet_n (ncp, contour, cont_normal,
860                                                inext, len);
861             } else {
862                draw_raw_segment_edge_n (ncp, contour, cont_normal,
863                                                inext, len);
864             }
865          } else {
866             if (no_norm) {
867                draw_raw_segment_color (ncp, contour, color_array, inext, len);
868             } else
869             if (__TUBE_DRAW_FACET_NORMALS) {
870                draw_raw_segment_c_and_facet_n (ncp, contour,
871                                                color_array,
872                                                cont_normal,
873                                                inext, len);
874             } else {
875                draw_raw_segment_c_and_edge_n (ncp, contour,
876                                               color_array,
877                                               cont_normal,
878                                               inext, len);
879              }
880           }
881       } else {
882 
883          /* else -- there are scales and offsets to deal with */
884          for (j=0; j<ncp; j++) {
885             MAT_DOT_VEC_2X3 ((&back_loop[3*j]),
886                              xform_array[inext], contour[j]);
887             back_loop[3*j+2] = -len;
888             front_loop[3*j+2] = 0.0;
889          }
890 
891          if (!no_norm) {
892             for (j=0; j<ncp; j++) {
893                NORM_XFORM_2X2 ( (&back_norm[3*j]),
894                                              xform_array[inext],
895                                              cont_normal [j]);
896             }
897          }
898 
899          if (no_cols) {
900             if (no_norm) {
901                draw_segment_plain (ncp, (gleVector *) front_loop,
902                                         (gleVector *) back_loop,
903                                         inext, len);
904             } else
905             if (__TUBE_DRAW_FACET_NORMALS) {
906                draw_binorm_segment_facet_n (ncp, (gleVector *) front_loop,
907                                                  (gleVector *) back_loop,
908                                                  (gleVector *) front_norm,
909                                                  (gleVector *) back_norm,
910                                                  inext, len);
911             } else {
912                draw_binorm_segment_edge_n (ncp, (gleVector *) front_loop,
913                                                 (gleVector *) back_loop,
914                                                 (gleVector *) front_norm,
915                                                 (gleVector *) back_norm,
916                                                 inext, len);
917             }
918             if (__TUBE_DRAW_CAP) {
919                 nrmv[2] = 1.0; N3F (nrmv);
920                 draw_front_contour_cap (ncp, (gleVector *) front_loop);
921                 nrmv[2] = -1.0; N3F (nrmv);
922                 draw_back_contour_cap (ncp, (gleVector *) back_loop);
923             }
924          } else {
925             if (no_norm) {
926                draw_segment_color (ncp,
927                                    (gleVector *) front_loop,
928                                    (gleVector *) back_loop,
929                                    color_array[inext-1],
930                                    color_array[inext],
931                                    inext, len);
932             } else
933             if (__TUBE_DRAW_FACET_NORMALS) {
934                draw_binorm_segment_c_and_facet_n (ncp,
935                                    (gleVector *) front_loop,
936                                    (gleVector *) back_loop,
937                                    (gleVector *) front_norm,
938                                    (gleVector *) back_norm,
939                                    color_array[inext-1],
940                                    color_array[inext],
941                                    inext, len);
942             } else {
943                draw_binorm_segment_c_and_edge_n (ncp,
944                                    (gleVector *) front_loop,
945                                    (gleVector *) back_loop,
946                                    (gleVector *) front_norm,
947                                    (gleVector *) back_norm,
948                                    color_array[inext-1],
949                                    color_array[inext],
950                                    inext, len);
951             }
952             if (__TUBE_DRAW_CAP) {
953                 C3F (color_array[inext-1]);
954                 nrmv[2] = 1.0; N3F (nrmv);
955                 draw_front_contour_cap (ncp, (gleVector *) front_loop);
956 
957                 C3F (color_array[inext]);
958                 nrmv[2] = -1.0; N3F (nrmv);
959                 draw_back_contour_cap (ncp, (gleVector *) back_loop);
960             }
961          }
962       }
963 
964       /* pop this matrix, do the next set */
965       POPMATRIX ();
966 
967       /* flop over transformed loops */
968       tmp = front_loop;
969       front_loop = back_loop;
970       back_loop = tmp;
971       tmp = front_norm;
972       front_norm = back_norm;
973       back_norm = tmp;
974 
975       i = inext;
976       /* ignore all segments of zero length */
977       FIND_NON_DEGENERATE_POINT (inext, npoints, len, diff, point_array);
978 
979    }
980 
981    /* free previously allocated memory, if any */
982    if (!no_xform) {
983       free (mem_anchor);
984    }
985 }
986 
987 /* ============================================================ */
988