1
2 /*
3 * MODULE NAME: ex_cut_round.c
4 *
5 * FUNCTION:
6 * This module contains code that draws extrusions with cut or round
7 * join styles. The cut join style is a beveled edge.
8 * The code also inserts colors and normals if appropriate.
9 *
10 * HISTORY:
11 * written by Linas Vepstas August/September 1991
12 * split into multiple compile units, Linas, October 1991
13 * added normal vectors Linas, October 1991
14 * Fixed filleting problem, Linas February 1993
15 * Modified to handle round joins as well (based on common code),
16 * Linas, March 1993
17 * work around OpenGL's lack of support for concave polys, June 1994
18 *
19 * Copyright (C) 1991,1993,1994,2003 Linas Vepstas <linas@linas.org>
20 */
21
22
23 #include <stdlib.h>
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h> /* for the memcpy() subroutine */
28
29 #include "gle.h"
30 #include "port.h"
31 #include "vvector.h"
32 #include "tube_gc.h"
33 #include "extrude.h"
34 #include "intersect.h"
35 #include "segment.h"
36
37 typedef void (*gleCapCallback) (int iloop,
38 double cap[][3],
39 float face_color[3],
40 gleDouble cut_vector[3],
41 gleDouble bisect_vector[3],
42 double norms[][3],
43 int frontwards);
44
45 #define INVALID_BUG_NEEDS_FIXING 0
46
47 #ifdef NONCONCAVE_CAPS
48
49 /* ============================================================ */
50 /*
51 * This subroutine draws a flat cap, to close off the cut ends
52 * of the cut-style join. Because OpenGL doe not natively handle
53 * concave polygons, this will cause some artifacts to appear on the
54 * screen.
55 */
56
57 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)58 draw_cut_style_cap_callback (int iloop,
59 double cap[][3],
60 float face_color[3],
61 gleDouble cut_vector[3],
62 gleDouble bisect_vector[3],
63 double norms[][3],
64 int frontwards)
65 {
66 int i;
67
68 if (face_color != NULL) C3F (face_color);
69
70 if (frontwards) {
71
72 /* if lighting is on, specify the endcap normal */
73 if (cut_vector != NULL) {
74 /* if normal pointing in wrong direction, flip it. */
75 if (cut_vector[2] < 0.0) {
76 VEC_SCALE (cut_vector, -1.0, cut_vector);
77 }
78 N3F_D (cut_vector);
79 }
80 BGNPOLYGON();
81 for (i=0; i<iloop; i++) {
82 V3F_D (cap[i], i, FRONT_CAP);
83 }
84 ENDPOLYGON();
85 } else {
86
87 /* if lighting is on, specify the endcap normal */
88 if (cut_vector != NULL) {
89 /* if normal pointing in wrong direction, flip it. */
90 if (cut_vector[2] > 0.0)
91 { VEC_SCALE (cut_vector, -1.0, cut_vector); }
92 N3F_D (cut_vector);
93 }
94 /* the sense of the loop is reversed for backfacing culling */
95 BGNPOLYGON();
96 for (i=iloop-1; i>-1; i--) {
97 V3F_D (cap[i], i, BACK_CAP);
98 }
99 ENDPOLYGON();
100 }
101
102 }
103
104 #else /* NONCONCAVE_CAPS */
105
106 /* ============================================================ */
107 /*
108 * This subroutine draws a flat cap, to close off the cut ends
109 * of the cut-style join. Properly handles concave endcaps.
110 */
111
112 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)113 draw_cut_style_cap_callback (int iloop,
114 double cap[][3],
115 float face_color[3],
116 gleDouble cut_vector[3],
117 gleDouble bisect_vector[3],
118 double norms[][3],
119 int frontwards)
120 {
121 #ifdef GL_32
122 int i;
123 #endif /* GL_32 */
124
125 #ifdef DELICATE_TESSELATOR
126 int i;
127 int is_colinear;
128 double *previous_vertex = 0x0;
129 double *first_vertex = 0x0;
130 #endif /* DELICATE_TESSELATOR */
131
132 #ifdef OPENGL_10
133 GLUtriangulatorObj *tobj;
134 tobj = gluNewTess ();
135 gluTessCallback (tobj, GLU_BEGIN, glBegin);
136 gluTessCallback (tobj, GLU_VERTEX, glVertex3dv);
137 gluTessCallback (tobj, GLU_END, glEnd);
138 #endif /* OPENGL_10 */
139
140 if (face_color != NULL) C3F (face_color);
141
142 if (frontwards) {
143
144 /* if lighting is on, specify the endcap normal */
145 if (cut_vector != NULL) {
146 /* if normal pointing in wrong direction, flip it. */
147 if (cut_vector[2] < 0.0) {
148 VEC_SCALE (cut_vector, -1.0, cut_vector);
149 }
150 N3F_D (cut_vector);
151 }
152 #ifdef GL_32
153 BGNPOLYGON();
154 for (i=0; i<iloop; i++) {
155 V3F_D (cap[i], i, FRONT_CAP);
156 }
157 ENDPOLYGON();
158 #endif /* GL_32 */
159 #ifdef OPENGL_10
160
161 /* If you have a tesselator that is happy with anything,
162 * including degenerate points, colinear segments, etc.
163 * then define this. Otherwise, pick one of the others.
164 *
165 * I beleive that the stock SGI tesselator is "lenient",
166 * despite explicit disclaimers in the documentation.
167 * (circa 1995).
168 *
169 * The Mesa tesselator is not at all forgiving of
170 * degenerate points.
171 * (circa 1997-1998)
172 */
173
174 #ifdef LENIENT_TESSELATOR
175 gluBeginPolygon (tobj);
176 for (i=0; i<iloop; i++) {
177 gluTessVertex (tobj, cap[i], cap[i]);
178 }
179 gluEndPolygon (tobj);
180 #endif /* LENIENT_TESSELATOR */
181
182 #ifdef DELICATE_TESSELATOR
183 gluBeginPolygon (tobj);
184
185 first_vertex = 0x0;
186 previous_vertex = cap[iloop-1];
187 for (i=0; i<iloop-1; i++) {
188 COLINEAR (is_colinear, previous_vertex, cap[i], cap[i+1]);
189 if (!is_colinear) {
190 gluTessVertex (tobj, cap[i], cap[i]);
191 previous_vertex = cap[i];
192 if (!first_vertex) first_vertex = previous_vertex;
193 }
194 }
195
196 if (!first_vertex) first_vertex = cap[0];
197 COLINEAR (is_colinear, previous_vertex, cap[iloop-1], first_vertex);
198 if (!is_colinear) gluTessVertex (tobj, cap[iloop-1], cap[iloop-1]);
199
200 gluEndPolygon (tobj);
201 #endif /* DELICATE_TESSELATOR */
202
203 #endif /* OPENGL_10 */
204 } else {
205
206 /* if lighting is on, specify the endcap normal */
207 if (cut_vector != NULL) {
208 /* if normal pointing in wrong direction, flip it. */
209 if (cut_vector[2] > 0.0) {
210 VEC_SCALE (cut_vector, -1.0, cut_vector);
211 }
212 N3F_D (cut_vector);
213 }
214 /* the sense of the loop is reversed for backfacing culling */
215 #ifdef GL_32
216 BGNPOLYGON();
217 for (i=iloop-1; i>-1; i--) {
218 V3F_D (cap[i], i, BACK_CAP);
219 }
220 ENDPOLYGON();
221 #endif /* GL_32 */
222 #ifdef OPENGL_10
223
224 #ifdef LENIENT_TESSELATOR
225 gluBeginPolygon (tobj);
226 for (i=iloop-1; i>-1; i--) {
227 gluTessVertex (tobj, cap[i], cap[i]);
228 }
229 gluEndPolygon (tobj);
230 #endif /* LENIENT_TESSELATOR */
231
232 #ifdef DELICATE_TESSELATOR
233 gluBeginPolygon (tobj);
234
235 first_vertex = 0x0;
236 previous_vertex = cap[0];
237 for (i=iloop-1; i>0; i--) {
238 COLINEAR (is_colinear, previous_vertex, cap[i], cap[i-1]);
239 if (!is_colinear) {
240 gluTessVertex (tobj, cap[i], cap[i]);
241 previous_vertex = cap[i];
242 if (!first_vertex) first_vertex = previous_vertex;
243 }
244 }
245
246 if (!first_vertex) first_vertex = cap[iloop-1];
247 COLINEAR (is_colinear, previous_vertex, cap[0], first_vertex);
248 if (!is_colinear) gluTessVertex (tobj, cap[0], cap[0]);
249
250 gluEndPolygon (tobj);
251 #endif /* DELICATE_TESSELATOR */
252
253 #endif /* OPENGL_10 */
254 }
255
256 #ifdef OPENGL_10
257 gluDeleteTess (tobj);
258 #endif /* OPENGL_10 */
259
260 }
261 #endif /* NONCONCAVE_ENDCAPS */
262
263 /* ============================================================ */
264 /*
265 * This subroutine matchs the cap callback template, but is a no-op
266 */
267
268 static 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)269 null_cap_callback (int iloop,
270 double cap[][3],
271 float face_color[3],
272 gleDouble cut_vector[3],
273 gleDouble bisect_vector[3],
274 double norms[][3],
275 int frontwards)
276 {}
277
278 /* ============================================================ */
279 /*
280 * This little routine draws the little idd-biddy fillet triangle with
281 * the right color, normal, etc.
282 *
283 * HACK ALERT -- there are two aspects to this routine/interface that
284 * are "unfinished".
285 * 1) the third point of the triangle should get a color thats
286 * interpolated beween the front and back color. The interpolant
287 * is not currently being computed. The error introduced by not
288 * doing this should be tiny and/or non-exitant in almost all
289 * expected uses of this code.
290 *
291 * 2) additional normal vectors should be supplied, and these should
292 * be interpolated to fit. Currently, this is not being done. As
293 * above, the expected error of not doing this should be tiny and/or
294 * non-existant in almost all expected uses of this code.
295 */
296 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])297 draw_fillet_triangle_plain
298 (gleDouble va[3],
299 gleDouble vb[3],
300 gleDouble vc[3],
301 int face,
302 float front_color[3],
303 float back_color[3])
304 {
305
306 if (front_color != NULL) C3F (front_color);
307 BGNTMESH (-5, 0.0);
308 if (face) {
309 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
310 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
311 } else {
312 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
313 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
314 }
315 V3F (vc, INVALID_BUG_NEEDS_FIXING, FILLET);
316 ENDTMESH ();
317
318 }
319
320 /* ============================================================ */
321 /*
322 * This little routine draws the little idd-biddy fillet triangle with
323 * the right color, normal, etc.
324 *
325 * HACK ALERT -- there are two aspects to this routine/interface that
326 * are "unfinished".
327 * 1) the third point of the triangle should get a color thats
328 * interpolated beween the front and back color. The interpolant
329 * is not currently being computed. The error introduced by not
330 * doing this should be tiny and/or non-exitant in almost all
331 * expected uses of this code.
332 *
333 * 2) additional normal vectors should be supplied, and these should
334 * be interpolated to fit. Currently, this is not being done. As
335 * above, the expected error of not doing this should be tiny and/or
336 * non-existant in almost all expected uses of this code.
337 */
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])338 static void draw_fillet_triangle_n_norms
339 (gleDouble va[3],
340 gleDouble vb[3],
341 gleDouble vc[3],
342 int face,
343 float front_color[3],
344 float back_color[3],
345 double na[3],
346 double nb[3])
347 {
348
349 if (front_color != NULL) C3F (front_color);
350 BGNTMESH (-5, 0.0);
351 if (__TUBE_DRAW_FACET_NORMALS) {
352 N3F_D (na);
353 if (face) {
354 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
355 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
356 } else {
357 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
358 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
359 }
360 V3F (vc, INVALID_BUG_NEEDS_FIXING, FILLET);
361 } else {
362 if (face) {
363 N3F_D (na);
364 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
365 N3F_D (nb);
366 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
367 } else {
368 N3F_D (nb);
369 V3F (vb, INVALID_BUG_NEEDS_FIXING, FILLET);
370 N3F_D (na);
371 V3F (va, INVALID_BUG_NEEDS_FIXING, FILLET);
372 N3F_D (nb);
373 }
374 V3F (vc, INVALID_BUG_NEEDS_FIXING, FILLET);
375 }
376 ENDTMESH ();
377
378 }
379
380 /* ============================================================ */
381
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,gleCapCallback cap_callback)382 static void draw_fillets_and_join_plain
383 (int ncp,
384 gleDouble trimmed_loop[][3],
385 gleDouble untrimmed_loop[][3],
386 int is_trimmed[],
387 gleDouble bis_origin[3],
388 gleDouble bis_vector[3],
389 float front_color[3],
390 float back_color[3],
391 gleDouble cut_vector[3],
392 int face,
393 gleCapCallback cap_callback)
394 {
395 int istop;
396 int icnt, icnt_prev, iloop;
397 double *cap_loop;
398 gleDouble sect[3];
399 gleDouble tmp_vec[3];
400 int save_style = 0;
401 int was_trimmed = FALSE;
402
403 cap_loop = (double *) malloc ((ncp+3)*3*sizeof (double));
404
405 /*
406 * If the first point is trimmed, keep going until one
407 * is found that is not trimmed, and start join there.
408 */
409
410 save_style = gleGetJoinStyle ();
411 icnt = 0;
412 iloop = 0;
413 if (!is_trimmed[0]) {
414
415 /* if the first point on the contour isn't trimmed, go ahead and
416 * drop an edge down to the bisecting plane, (thus starting the
417 * join). (Only need to do this for cut join, its bad if done for
418 * round join). (Also, do this only for open contours; leads to
419 * bugs when done for closed contours).
420 */
421 if ((__TUBE_CUT_JOIN) && (!(save_style & TUBE_CONTOUR_CLOSED))) {
422 VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector);
423 INNERSECT (sect,
424 bis_origin,
425 bis_vector,
426 trimmed_loop[0],
427 tmp_vec);
428 VEC_COPY ( (&cap_loop[3*iloop]), sect);
429 iloop ++;
430 }
431 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0]));
432 iloop++;
433 icnt_prev = icnt;
434 icnt ++;
435 } else {
436
437 /* else, loop until an untrimmed point is found */
438 was_trimmed = TRUE;
439 while (is_trimmed[icnt]) {
440 icnt_prev = icnt;
441 icnt ++;
442 if (icnt >= ncp) {
443 free (cap_loop);
444 return; /* oops - everything was trimmed */
445 }
446 }
447 }
448
449 /* Start walking around the end cap. Every time the end loop is
450 * trimmed, we know we'll need to draw a fillet triangle. In
451 * addition, after every pair of visibility changes, we draw a cap. */
452 if (__TUBE_CLOSE_CONTOUR) {
453 istop = ncp;
454 } else {
455 istop = ncp-1;
456 }
457
458 /* save the join style, and disable a closed contour.
459 * Need to do this so partial contours don't close up. */
460 gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED);
461
462 for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) {
463
464 /* There are four interesting cases for drawing caps and fillets:
465 * 1) this & previous point were trimmed. Don't do anything,
466 * advance counter.
467 * 2) this point trimmed, previous not -- draw fillet, and
468 * draw cap.
469 * 3) this point not trimmed, previous one was -- compute
470 * intersection point, draw fillet with it, and save
471 * point for cap contour.
472 * 4) this & previous point not trimmed -- save for endcap.
473 */
474
475 /* Case 1 -- noop, just advance pointers */
476 if (is_trimmed[icnt_prev] && is_trimmed[icnt]) {
477 }
478
479 /* Case 2 -- Hah! first point! compute intersect & draw fillet! */
480 if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
481
482 /* important note: the array "untrimmed" contains valid
483 * untrimmed data ONLY when is_trim is TRUE. Otherwise,
484 * only "trim" containes valid data */
485
486 /* compute intersection */
487 INNERSECT (sect,
488 bis_origin,
489 bis_vector,
490 untrimmed_loop[icnt_prev],
491 trimmed_loop[icnt]);
492
493 /* Draw Fillet */
494 draw_fillet_triangle_plain (trimmed_loop[icnt_prev],
495 trimmed_loop[icnt],
496 sect,
497 face,
498 front_color,
499 back_color);
500
501 VEC_COPY ( (&cap_loop[3*iloop]), sect);
502 iloop ++;
503 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt]));
504 iloop++;
505 }
506
507 /* Case 3 -- add to collection of points */
508 if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
509 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt]));
510 iloop++;
511 }
512
513 /* Case 4 -- Hah! last point! draw fillet & draw cap! */
514 if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) {
515 was_trimmed = TRUE;
516
517 /* important note: the array "untrimmed" contains valid
518 * untrimmed data ONLY when is_trim is TRUE. Otherwise,
519 * only "trim" containes valid data */
520
521 /* compute intersection */
522 INNERSECT (sect,
523 bis_origin,
524 bis_vector,
525 trimmed_loop[icnt_prev],
526 untrimmed_loop[icnt]);
527
528 /* Draw Fillet */
529 draw_fillet_triangle_plain (trimmed_loop[icnt_prev],
530 trimmed_loop[icnt],
531 sect,
532 face,
533 front_color,
534 back_color);
535
536 VEC_COPY ( (&cap_loop[3*iloop]), sect);
537 iloop ++;
538
539 /* draw cap */
540 if (iloop >= 3) (*cap_callback) (iloop,
541 (gleDouble (*)[3]) cap_loop,
542 front_color,
543 cut_vector,
544 bis_vector,
545 NULL,
546 face);
547
548 /* reset cap counter */
549 iloop = 0;
550 }
551 }
552
553 /* now, finish up in the same way that we started. If the last
554 * point of the contour is visible, drop an edge to the bisecting
555 * plane, thus finishing the join, and then, draw the join! */
556
557 icnt --; /* decrement to make up for loop exit condititons */
558 icnt += ncp;
559 icnt %= ncp;
560 if ((!is_trimmed[icnt]) && (iloop >= 2)) {
561
562 VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector);
563 INNERSECT (sect,
564 bis_origin,
565 bis_vector,
566 trimmed_loop[icnt],
567 tmp_vec);
568 VEC_COPY ( (&cap_loop[3*iloop]), sect);
569 iloop ++;
570
571 /* if nothing was ever trimmed, then we want to draw the
572 * cap the way the user asked for it -- closed or not closed.
573 * Therefore, reset the closure flag to its original state.
574 */
575 if (!was_trimmed) {
576 gleSetJoinStyle (save_style);
577 }
578
579 /* draw cap */
580 (*cap_callback) (iloop,
581 (gleDouble (*)[3]) cap_loop,
582 front_color,
583 cut_vector,
584 bis_vector,
585 NULL,
586 face);
587 }
588
589 /* rest to the saved style */
590 gleSetJoinStyle (save_style);
591 free (cap_loop);
592 }
593
594 /* ============================================================ */
595
596 static 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,gleCapCallback cap_callback)597 draw_fillets_and_join_n_norms
598 (int ncp,
599 gleDouble trimmed_loop[][3],
600 gleDouble untrimmed_loop[][3],
601 int is_trimmed[],
602 gleDouble bis_origin[3],
603 gleDouble bis_vector[3],
604 double normals[][3],
605 float front_color[3],
606 float back_color[3],
607 gleDouble cut_vector[3],
608 int face,
609 gleCapCallback cap_callback)
610 {
611 int istop;
612 int icnt, icnt_prev, iloop;
613 double *cap_loop, *norm_loop;
614 gleDouble sect[3];
615 gleDouble tmp_vec[3];
616 int save_style = 0;
617 int was_trimmed = FALSE;
618
619 save_style = gleGetJoinStyle ();
620 cap_loop = (double *) malloc ((ncp+3)*3*2*sizeof (double));
621 norm_loop = cap_loop + (ncp+3)*3;
622
623 /*
624 * If the first point is trimmed, keep going until one
625 * is found that is not trimmed, and start join there.
626 */
627
628 icnt = 0;
629 iloop = 0;
630 if (!is_trimmed[0]) {
631
632 /* if the first point on the contour isn't trimmed, go ahead and
633 * drop an edge down to the bisecting plane, (thus starting the
634 * join). (Only need to do this for cut join, its bad if done for
635 * round join). (Also, leads to bugs when done for closed
636 * contours ... do this only if contour is open).
637 */
638 if ((__TUBE_CUT_JOIN) && (!(save_style & TUBE_CONTOUR_CLOSED))) {
639 VEC_SUM (tmp_vec, trimmed_loop[0], bis_vector);
640 INNERSECT (sect,
641 bis_origin,
642 bis_vector,
643 trimmed_loop[0],
644 tmp_vec);
645 VEC_COPY ( (&cap_loop[3*iloop]), sect);
646 VEC_COPY ( (&norm_loop[3*iloop]), normals[0]);
647 iloop ++;
648 }
649 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[0]));
650 VEC_COPY ( (&norm_loop[3*iloop]), normals[0]);
651 iloop++;
652 icnt_prev = icnt;
653 icnt ++;
654 } else {
655
656 /* else, loop until an untrimmed point is found */
657 was_trimmed = TRUE;
658 while (is_trimmed[icnt]) {
659 icnt_prev = icnt;
660 icnt ++;
661 if (icnt >= ncp) {
662 free (cap_loop);
663 return; /* oops - everything was trimmed */
664 }
665 }
666 }
667
668 /* Start walking around the end cap. Every time the end loop is
669 * trimmed, we know we'll need to draw a fillet triangle. In
670 * addition, after every pair of visibility changes, we draw a cap. */
671 if (__TUBE_CLOSE_CONTOUR) {
672 istop = ncp;
673 } else {
674 istop = ncp-1;
675 }
676
677 /* save the join style, and disable a closed contour.
678 * Need to do this so partial contours don't close up. */
679 save_style = gleGetJoinStyle ();
680 gleSetJoinStyle (save_style & ~TUBE_CONTOUR_CLOSED);
681
682 for (; icnt_prev < istop; icnt_prev ++, icnt ++, icnt %= ncp) {
683
684 /* There are four interesting cases for drawing caps and fillets:
685 * 1) this & previous point were trimmed. Don't do anything,
686 * advance counter.
687 * 2) this point trimmed, previous not -- draw fillet, and
688 * draw cap.
689 * 3) this point not trimmed, previous one was -- compute
690 * intersection point, draw fillet with it, and save
691 * point for cap contour.
692 * 4) this & previous point not trimmed -- save for endcap.
693 */
694
695 /* Case 1 -- noop, just advance pointers */
696 if (is_trimmed[icnt_prev] && is_trimmed[icnt]) {
697 }
698
699 /* Case 2 -- Hah! first point! compute intersect & draw fillet! */
700 if (is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
701
702 /* important note: the array "untrimmed" contains valid
703 * untrimmed data ONLY when is_trim is TRUE. Otherwise,
704 * only "trim" containes valid data */
705
706 /* compute intersection */
707 INNERSECT (sect,
708 bis_origin,
709 bis_vector,
710 untrimmed_loop[icnt_prev],
711 trimmed_loop[icnt]);
712
713 /* Draw Fillet */
714 draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev],
715 trimmed_loop[icnt],
716 sect,
717 face,
718 front_color,
719 back_color,
720 normals[icnt_prev],
721 normals[icnt]);
722 VEC_COPY ( (&cap_loop[3*iloop]), sect);
723 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]);
724 iloop ++;
725 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt]));
726 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
727 iloop++;
728 }
729
730 /* Case 3 -- add to collection of points */
731 if (!is_trimmed[icnt_prev] && !is_trimmed[icnt]) {
732 VEC_COPY ( (&cap_loop[3*iloop]), (trimmed_loop[icnt]));
733 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
734 iloop++;
735 }
736
737 /* Case 4 -- Hah! last point! draw fillet & draw cap! */
738 if (!is_trimmed[icnt_prev] && is_trimmed[icnt]) {
739 was_trimmed = TRUE;
740
741 /* important note: the array "untrimmed" contains valid
742 * untrimmed data ONLY when is_trim is TRUE. Otherwise,
743 * only "trim" containes valid data */
744
745 /* compute intersection */
746 INNERSECT (sect,
747 bis_origin,
748 bis_vector,
749 trimmed_loop[icnt_prev],
750 untrimmed_loop[icnt]);
751
752 /* Draw Fillet */
753 draw_fillet_triangle_n_norms (trimmed_loop[icnt_prev],
754 trimmed_loop[icnt],
755 sect,
756 face,
757 front_color,
758 back_color,
759 normals[icnt_prev],
760 normals[icnt]);
761
762 VEC_COPY ( (&cap_loop[3*iloop]), sect);
763
764 /* OK, maybe phong normals are wrong, but at least facet
765 * normals will come out OK. */
766 if (__TUBE_DRAW_FACET_NORMALS) {
767 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt_prev]);
768 } else {
769 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
770 }
771 iloop ++;
772
773 /* draw cap */
774 if (iloop >= 3) (*cap_callback) (iloop,
775 (gleVector *) cap_loop,
776 front_color,
777 cut_vector,
778 bis_vector,
779 (gleVector *) norm_loop,
780 face);
781
782 /* reset cap counter */
783 iloop = 0;
784 }
785 }
786
787 /* now, finish up in the same way that we started. */
788
789 icnt --; /* decrement to make up for loop exit condititons */
790 icnt += ncp;
791 icnt %= ncp;
792 if ((!is_trimmed[icnt]) && (iloop >= 2)) {
793
794 /* If the last point of the contour is visible, drop an edge
795 * to the bisecting plane, thus finishing the join.
796 * Note that doing this leads to bugs if done for closed
797 * contours ... do this only if contour is open.
798 */
799 if ((__TUBE_CUT_JOIN) && (!(save_style & TUBE_CONTOUR_CLOSED))) {
800 VEC_SUM (tmp_vec, trimmed_loop[icnt], bis_vector);
801 INNERSECT (sect,
802 bis_origin,
803 bis_vector,
804 trimmed_loop[icnt],
805 tmp_vec);
806 VEC_COPY ( (&cap_loop[3*iloop]), sect);
807 VEC_COPY ( (&norm_loop[3*iloop]), normals[icnt]);
808 iloop ++;
809 }
810
811 /* if nothing was ever trimmed, then we want to draw the
812 * cap the way the user asked for it -- closed or not closed.
813 * Therefore, reset the closure flag to its original state.
814 */
815 if (!was_trimmed) {
816 gleSetJoinStyle (save_style);
817 }
818 /* draw cap */
819 (*cap_callback) (iloop,
820 (gleVector *) cap_loop,
821 front_color,
822 cut_vector,
823 bis_vector,
824 (gleVector *) norm_loop,
825 face);
826 }
827
828 /* rest to the saved style */
829 gleSetJoinStyle (save_style);
830 free (cap_loop);
831 }
832
833 /* ============================================================ */
834 /* This routine draws "cut" style extrusions.
835 */
836
837 void
extrusion_round_or_cut_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])838 extrusion_round_or_cut_join (int ncp, /* number of contour points */
839 gleDouble contour[][2], /* 2D contour */
840 gleDouble cont_normal[][2],/* 2D normal vecs */
841 gleDouble up[3], /* up vector for contour */
842 int npoints, /* numpoints in poly-line */
843 gleDouble point_array[][3], /* polyline */
844 gleColor color_array[], /* color of polyline */
845 gleDouble xform_array[][2][3]) /* 2D contour xforms */
846 {
847 int i, j;
848 int inext, inextnext;
849 gleDouble m[4][4];
850 gleDouble tube_len, seg_len;
851 gleDouble diff[3];
852 gleDouble bi_0[3], bi_1[3]; /* bisecting plane */
853 gleDouble bisector_0[3], bisector_1[3]; /* bisecting plane */
854 gleDouble cut_0[3], cut_1[3]; /* cutting planes */
855 gleDouble lcut_0[3], lcut_1[3]; /* cutting planes */
856 int valid_cut_0, valid_cut_1; /* flag -- cut vector is valid */
857 gleDouble end_point_0[3], end_point_1[3];
858 gleDouble torsion_point_0[3], torsion_point_1[3];
859 gleDouble isect_point[3];
860 gleDouble origin[3], neg_z[3];
861 gleDouble yup[3]; /* alternate up vector */
862 gleDouble *front_cap, *back_cap; /* arrays containing the end caps */
863 gleDouble *front_loop, *back_loop; /* arrays containing the tube ends */
864 double *front_norm, *back_norm; /* arrays containing normal vecs */
865 double *norm_loop=0x0, *tmp; /* normal vectors, cast into 3d from 2d */
866 int *front_is_trimmed, *back_is_trimmed; /* T or F */
867 float *front_color, *back_color; /* pointers to segment colors */
868 gleCapCallback cap_callback = 0x0 ; /* function callback to draw cap */
869 gleCapCallback tmp_cap_callback = 0x0; /* function callback to draw cap */
870 int join_style_is_cut; /* TRUE if join style is cut */
871 double dot; /* partial dot product */
872 char *mem_anchor;
873 int first_time = TRUE;
874 gleDouble *cut_vec;
875
876 /* create a local, block scope copy of of the join style.
877 * this will alleviate wasted cycles and register write-backs */
878 /* choose the right callback, depending on the choosen join style */
879 if (__TUBE_CUT_JOIN) {
880 join_style_is_cut = TRUE;
881 cap_callback = draw_cut_style_cap_callback;
882 } else {
883 join_style_is_cut = FALSE;
884 cap_callback = draw_round_style_cap_callback;
885 }
886
887 /* By definition, the contour passed in has its up vector pointing in
888 * the y direction */
889 if (up == NULL) {
890 yup[0] = 0.0;
891 yup[1] = 1.0;
892 yup[2] = 0.0;
893 } else {
894 VEC_COPY (yup, up);
895 }
896
897 /* ========== "up" vector sanity check ========== */
898 (void) up_sanity_check (yup, npoints, point_array);
899
900 /* the origin is at the origin */
901 origin [0] = 0.0;
902 origin [1] = 0.0;
903 origin [2] = 0.0;
904
905 /* and neg_z is at neg z */
906 neg_z[0] = 0.0;
907 neg_z[1] = 0.0;
908 neg_z[2] = 1.0;
909
910 /* malloc the data areas that we'll need to store the end-caps */
911 mem_anchor = malloc (4 * 3*ncp*sizeof(gleDouble)
912 + 2 * 3*ncp*sizeof(double)
913 + 2 * 1*ncp*sizeof(int));
914 front_norm = (double *) mem_anchor;
915 back_norm = front_norm + 3*ncp;
916 front_loop = (gleDouble *) (back_norm + 3*ncp);
917 back_loop = front_loop + 3*ncp;
918 front_cap = back_loop + 3*ncp;
919 back_cap = front_cap + 3*ncp;
920 front_is_trimmed = (int *) (back_cap + 3*ncp);
921 back_is_trimmed = front_is_trimmed + ncp;
922
923 /* ======================================= */
924
925 /* |-|-|-|-|-|-|-|-| SET UP FOR FIRST SEGMENT |-|-|-|-|-|-|-| */
926
927 /* ignore all segments of zero length */
928 i = 1;
929 inext = i;
930 FIND_NON_DEGENERATE_POINT (inext, npoints, seg_len, diff, point_array);
931 tube_len = seg_len; /* store for later use */
932
933 /* may as well get the normals set up now */
934 if (cont_normal != NULL) {
935 if (xform_array == NULL) {
936 norm_loop = front_norm;
937 back_norm = norm_loop;
938 for (j=0; j<ncp; j++) {
939 norm_loop[3*j] = cont_normal[j][0];
940 norm_loop[3*j+1] = cont_normal[j][1];
941 norm_loop[3*j+2] = 0.0;
942 }
943 } else {
944 for (j=0; j<ncp; j++) {
945 NORM_XFORM_2X2 ( (&front_norm[3*j]),
946 xform_array[inext-1],
947 cont_normal [j]);
948 front_norm[3*j+2] = 0.0;
949 back_norm[3*j+2] = 0.0;
950 }
951 }
952 } else {
953 front_norm = back_norm = norm_loop = NULL;
954 }
955
956 /* get the bisecting plane */
957 bisecting_plane (bi_0, point_array[i-1],
958 point_array[i],
959 point_array[inext]);
960
961 /* compute cutting plane */
962 CUTTING_PLANE (valid_cut_0, cut_0, point_array[i-1],
963 point_array[i],
964 point_array[inext]);
965
966 /* reflect the up vector in the bisecting plane */
967 VEC_REFLECT (yup, yup, bi_0);
968
969 /* |-|-|-|-|-|-|-|-| START LOOP OVER SEGMENTS |-|-|-|-|-|-|-| */
970
971 /* draw tubing, not doing the first segment */
972 while (inext<npoints-1) {
973
974 inextnext = inext;
975 /* ignore all segments of zero length */
976 FIND_NON_DEGENERATE_POINT (inextnext, npoints,
977 seg_len, diff, point_array);
978
979 /* get the far bisecting plane */
980 bisecting_plane (bi_1, point_array[i],
981 point_array[inext],
982 point_array[inextnext]);
983
984
985 /* compute cutting plane */
986 CUTTING_PLANE (valid_cut_1, cut_1, point_array[i],
987 point_array[inext],
988 point_array[inextnext]);
989
990 /* rotate so that z-axis points down v2-v1 axis,
991 * and so that origen is at v1 */
992 uviewpoint (m, point_array[i], point_array[inext], yup);
993 PUSHMATRIX ();
994 MULTMATRIX (m);
995
996 /* rotate the cutting planes into the local coordinate system */
997 MAT_DOT_VEC_3X3 (lcut_0, m, cut_0);
998 MAT_DOT_VEC_3X3 (lcut_1, m, cut_1);
999
1000 /* rotate the bisecting planes into the local coordinate system */
1001 MAT_DOT_VEC_3X3 (bisector_0, m, bi_0);
1002 MAT_DOT_VEC_3X3 (bisector_1, m, bi_1);
1003
1004
1005 neg_z[2] = -tube_len;
1006
1007 /* draw the tube */
1008 /* --------- START OF TMESH GENERATION -------------- */
1009 for (j=0; j<ncp; j++) {
1010
1011 /* set up the endpoints for segment clipping */
1012 if (xform_array == NULL) {
1013 VEC_COPY_2 (end_point_0, contour[j]);
1014 VEC_COPY_2 (end_point_1, contour[j]);
1015 VEC_COPY_2 (torsion_point_0, contour[j]);
1016 VEC_COPY_2 (torsion_point_1, contour[j]);
1017 } else {
1018 /* transform the contour points with the local xform */
1019 MAT_DOT_VEC_2X3 (end_point_0,
1020 xform_array[inext-1], contour[j]);
1021 MAT_DOT_VEC_2X3 (torsion_point_0,
1022 xform_array[inext], contour[j]);
1023 MAT_DOT_VEC_2X3 (end_point_1,
1024 xform_array[inext], contour[j]);
1025 MAT_DOT_VEC_2X3 (torsion_point_1,
1026 xform_array[inext-1], contour[j]);
1027
1028 /* if there are normals and there are affine xforms,
1029 * then compute local coordinate system normals.
1030 * Set up the back normals. (The front normals we inherit
1031 * from previous pass through the loop). */
1032 if (cont_normal != NULL) {
1033 /* do up the normal vectors with the inverse transpose */
1034 NORM_XFORM_2X2 ( (&back_norm[3*j]),
1035 xform_array[inext],
1036 cont_normal [j]);
1037 }
1038 }
1039 end_point_0 [2] = 0.0;
1040 torsion_point_0 [2] = 0.0;
1041 end_point_1 [2] = - tube_len;
1042 torsion_point_1 [2] = - tube_len;
1043
1044 /* The two end-points define a line. Intersect this line
1045 * against the clipping plane defined by the PREVIOUS
1046 * tube segment. */
1047
1048 /* if this and the last tube are co-linear, don't cut the angle
1049 * if you do, a divide by zero will result. This and last tube
1050 * are co-linear when the cut vector is of zero length */
1051 if (valid_cut_0 && join_style_is_cut) {
1052 INNERSECT (isect_point, /* isect point (returned) */
1053 origin, /* point on intersecting plane */
1054 lcut_0, /* normal vector to plane */
1055 end_point_0, /* point on line */
1056 end_point_1); /* another point on the line */
1057
1058 /* determine whether the raw end of the extrusion would have
1059 * been cut, by checking to see if the raw and is on the
1060 * far end of the half-plane defined by the cut vector.
1061 * If the raw end is not "cut", then it is "trimmed".
1062 */
1063 if (lcut_0[2] < 0.0) { VEC_SCALE (lcut_0, -1.0, lcut_0); }
1064 dot = lcut_0[0] * end_point_0[0];
1065 dot += lcut_0[1] * end_point_0[1];
1066
1067 VEC_COPY ((&front_loop[3*j]), isect_point);
1068 } else {
1069 /* actual value of dot not interseting; need
1070 * only be positive so that if test below failes */
1071 dot = 1.0;
1072 VEC_COPY ((&front_loop[3*j]), end_point_0);
1073 }
1074
1075 INNERSECT (isect_point, /* intersection point (returned) */
1076 origin, /* point on intersecting plane */
1077 bisector_0, /* normal vector to plane */
1078 end_point_0, /* point on line */
1079 torsion_point_1); /* another point on the line */
1080
1081 /* trim out interior of intersecting tube */
1082 /* ... but save the untrimmed version for drawing the endcaps */
1083 /* ... note that cap contains valid data ONLY when is_trimmed
1084 * is TRUE. */
1085 if ((dot <= 0.0) || (isect_point[2] < front_loop[3*j+2])) {
1086 /*
1087 if ((dot <= 0.0) || (front_loop[3*j+2] > 0.0)) {
1088 */
1089 VEC_COPY ((&front_cap[3*j]), (&front_loop [3*j]));
1090 VEC_COPY ((&front_loop[3*j]), isect_point);
1091 front_is_trimmed[j] = TRUE;
1092 } else {
1093 front_is_trimmed[j] = FALSE;
1094 }
1095
1096 /* if intersection is behind the end of the segment,
1097 * truncate to the end of the segment
1098 * Note that coding front_loop [3*j+2] = -tube_len;
1099 * doesn't work when twists are involved, */
1100 if (front_loop[3*j+2] < -tube_len) {
1101 VEC_COPY( (&front_loop[3*j]), end_point_1);
1102 }
1103
1104 /* --------------------------------------------------- */
1105 /* The two end-points define a line. We did one endpoint
1106 * above. Now do the other.Intersect this line
1107 * against the clipping plane defined by the NEXT
1108 * tube segment. */
1109
1110 /* if this and the last tube are co-linear, don't cut the angle
1111 * if you do, a divide by zero will result. This and last tube
1112 * are co-linear when the cut vector is of zero length */
1113 if (valid_cut_1 && join_style_is_cut) {
1114 INNERSECT (isect_point, /* isect point (returned) */
1115 neg_z, /* point on intersecting plane */
1116 lcut_1, /* normal vector to plane */
1117 end_point_1, /* point on line */
1118 end_point_0); /* another point on the line */
1119
1120 if (lcut_1[2] > 0.0) { VEC_SCALE (lcut_1, -1.0, lcut_1); }
1121 dot = lcut_1[0] * end_point_1[0];
1122 dot += lcut_1[1] * end_point_1[1];
1123
1124
1125 VEC_COPY ((&back_loop[3*j]), isect_point);
1126 } else {
1127 /* actual value of dot not interseting; need
1128 * only be positive so that if test below failes */
1129 dot = 1.0;
1130 VEC_COPY ((&back_loop[3*j]), end_point_1);
1131 }
1132
1133 INNERSECT (isect_point, /* intersection point (returned) */
1134 neg_z, /* point on intersecting plane */
1135 bisector_1, /* normal vector to plane */
1136 torsion_point_0, /* point on line */
1137 end_point_1); /* another point on the line */
1138
1139 /* cut out interior of intersecting tube */
1140 /* ... but save the uncut version for drawing the endcaps */
1141 /* ... note that cap contains valid data ONLY when is
1142 *_trimmed is TRUE. */
1143 /*
1144 if ((dot <= 0.0) || (back_loop[3*j+2] < -tube_len)) {
1145 */
1146 if ((dot <= 0.0) || (isect_point[2] > back_loop[3*j+2])) {
1147 VEC_COPY ((&back_cap[3*j]), (&back_loop [3*j]));
1148 VEC_COPY ((&back_loop[3*j]), isect_point);
1149 back_is_trimmed[j] = TRUE;
1150 } else {
1151 back_is_trimmed[j] = FALSE;
1152 }
1153
1154 /* if intersection is behind the end of the segment,
1155 * truncate to the end of the segment
1156 * Note that coding back_loop [3*j+2] = 0.0;
1157 * doesn't work when twists are involved, */
1158 if (back_loop[3*j+2] > 0.0) {
1159 VEC_COPY( (&back_loop[3*j]), end_point_0);
1160 }
1161 }
1162
1163 /* --------- END OF TMESH GENERATION -------------- */
1164
1165 /* |||||||||||||||||| START SEGMENT DRAW |||||||||||||||||||| */
1166 /* There are six different cases we can have for presence and/or
1167 * absecnce of colors and normals, and for interpretation of
1168 * normals. The blechy set of nested if statements below
1169 * branch to each of the six cases */
1170 if (xform_array == NULL) {
1171 if (color_array == NULL) {
1172 if (cont_normal == NULL) {
1173 draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len);
1174 } else
1175 if (__TUBE_DRAW_FACET_NORMALS) {
1176 draw_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
1177 inext, seg_len);
1178 } else {
1179 draw_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
1180 inext, seg_len);
1181 }
1182 } else {
1183 if (cont_normal == NULL) {
1184 draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
1185 color_array[inext-1],
1186 color_array[inext], inext, seg_len);
1187 } else
1188 if (__TUBE_DRAW_FACET_NORMALS) {
1189 draw_segment_c_and_facet_n (ncp,
1190 (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
1191 color_array[inext-1],
1192 color_array[inext], inext, seg_len);
1193 } else {
1194 draw_segment_c_and_edge_n (ncp,
1195 (gleVector *) front_loop, (gleVector *) back_loop, (gleVector *) norm_loop,
1196 color_array[inext-1],
1197 color_array[inext], inext, seg_len);
1198 }
1199 }
1200 } else {
1201 if (color_array == NULL) {
1202 if (cont_normal == NULL) {
1203 draw_segment_plain (ncp, (gleVector *) front_loop, (gleVector *) back_loop, inext, seg_len);
1204 } else
1205 if (__TUBE_DRAW_FACET_NORMALS) {
1206 draw_binorm_segment_facet_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
1207 (gleVector *) front_norm, (gleVector *) back_norm,
1208 inext, seg_len);
1209 } else {
1210 draw_binorm_segment_edge_n (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
1211 (gleVector *) front_norm, (gleVector *) back_norm,
1212 inext, seg_len);
1213 }
1214 } else {
1215 if (cont_normal == NULL) {
1216 draw_segment_color (ncp, (gleVector *) front_loop, (gleVector *) back_loop,
1217 color_array[inext-1],
1218 color_array[inext], inext, seg_len);
1219 } else
1220 if (__TUBE_DRAW_FACET_NORMALS) {
1221 draw_binorm_segment_c_and_facet_n (ncp,
1222 (gleVector *) front_loop, (gleVector *) back_loop,
1223 (gleVector *) front_norm, (gleVector *) back_norm,
1224 color_array[inext-1],
1225 color_array[inext], inext, seg_len);
1226 } else {
1227 draw_binorm_segment_c_and_edge_n (ncp,
1228 (gleVector *) front_loop, (gleVector *) back_loop,
1229 (gleVector *) front_norm, (gleVector *) back_norm,
1230 color_array[inext-1],
1231 color_array[inext], inext, seg_len);
1232 }
1233 }
1234 }
1235 /* |||||||||||||||||| END SEGMENT DRAW |||||||||||||||||||| */
1236
1237 /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1238
1239 /* if end caps are required, draw them. But don't draw any
1240 * but the very first and last caps */
1241 if (first_time) {
1242 first_time = FALSE;
1243 tmp_cap_callback = cap_callback;
1244 cap_callback = null_cap_callback;
1245 if (__TUBE_DRAW_CAP) {
1246 if (color_array != NULL) C3F (color_array[inext-1]);
1247 draw_angle_style_front_cap (ncp, bisector_0,
1248 (gleVector *) front_loop);
1249 }
1250 }
1251 /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1252
1253 /* $$$$$$$$$$$$$$$$ BEGIN -1, FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */
1254 /*
1255 * Now, draw the fillet triangles, and the join-caps.
1256 */
1257 if (color_array != NULL) {
1258 front_color = color_array[inext-1];
1259 back_color = color_array[inext];
1260 } else {
1261 front_color = NULL;
1262 back_color = NULL;
1263 }
1264
1265 if (cont_normal == NULL) {
1266 /* the flag valid-cut is true if the cut vector has a valid
1267 * value (i.e. if a degenerate case has not occured).
1268 */
1269 if (valid_cut_0) {
1270 cut_vec = lcut_0;
1271 } else {
1272 cut_vec = NULL;
1273 }
1274 draw_fillets_and_join_plain (ncp,
1275 (gleVector *) front_loop,
1276 (gleVector *) front_cap,
1277 front_is_trimmed,
1278 origin,
1279 bisector_0,
1280 front_color,
1281 back_color,
1282 cut_vec,
1283 TRUE,
1284 cap_callback);
1285
1286 /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1287 if (inext == npoints-2) {
1288 if (__TUBE_DRAW_CAP) {
1289 if (color_array != NULL) C3F (color_array[inext]);
1290 draw_angle_style_back_cap (ncp, bisector_1,
1291 (gleVector *) back_loop);
1292 cap_callback = null_cap_callback;
1293 }
1294 } else {
1295 /* restore ability to draw cap */
1296 cap_callback = tmp_cap_callback;
1297 }
1298 /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1299
1300 /* the flag valid-cut is true if the cut vector has a valid
1301 * value (i.e. if a degenerate case has not occured).
1302 */
1303 if (valid_cut_1) {
1304 cut_vec = lcut_1;
1305 } else {
1306 cut_vec = NULL;
1307 }
1308 draw_fillets_and_join_plain (ncp,
1309 (gleVector *) back_loop,
1310 (gleVector *) back_cap,
1311 back_is_trimmed,
1312 neg_z,
1313 bisector_1,
1314 back_color,
1315 front_color,
1316 cut_vec,
1317 FALSE,
1318 cap_callback);
1319 } else {
1320
1321 /* the flag valid-cut is true if the cut vector has a valid
1322 * value (i.e. if a degenerate case has not occured).
1323 */
1324 if (valid_cut_0) {
1325 cut_vec = lcut_0;
1326 } else {
1327 cut_vec = NULL;
1328 }
1329 draw_fillets_and_join_n_norms (ncp,
1330 (gleVector *) front_loop,
1331 (gleVector *) front_cap,
1332 front_is_trimmed,
1333 origin,
1334 bisector_0,
1335 (gleVector *) front_norm,
1336 front_color,
1337 back_color,
1338 cut_vec,
1339 TRUE,
1340 cap_callback);
1341
1342 /* v^v^v^v^v^v^v^v^v BEGIN END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1343 if (inext == npoints-2) {
1344 if (__TUBE_DRAW_CAP) {
1345 if (color_array != NULL) C3F (color_array[inext]);
1346 draw_angle_style_back_cap (ncp, bisector_1,
1347 (gleDouble (*)[3]) back_loop);
1348 cap_callback = null_cap_callback;
1349 }
1350 } else {
1351 /* restore ability to draw cap */
1352 cap_callback = tmp_cap_callback;
1353 }
1354 /* v^v^v^v^v^v^v^v^v END END CAPS v^v^v^v^v^v^v^v^v^v^v^v */
1355
1356 /* the flag valid-cut is true if the cut vector has a valid
1357 * value (i.e. if a degenerate case has not occured).
1358 */
1359 if (valid_cut_1) {
1360 cut_vec = lcut_1;
1361 } else {
1362 cut_vec = NULL;
1363 }
1364 draw_fillets_and_join_n_norms (ncp,
1365 (gleVector *) back_loop,
1366 (gleVector *) back_cap,
1367 back_is_trimmed,
1368 neg_z,
1369 bisector_1,
1370 (gleVector *) back_norm,
1371 back_color,
1372 front_color,
1373 cut_vec,
1374 FALSE,
1375 cap_callback);
1376 }
1377
1378 /* $$$$$$$$$$$$$$$$ END FILLET & JOIN DRAW $$$$$$$$$$$$$$$$$ */
1379
1380 /* pop this matrix, do the next set */
1381 POPMATRIX ();
1382
1383 /* slosh stuff over to next vertex */
1384 tmp = front_norm;
1385 front_norm = back_norm;
1386 back_norm = tmp;
1387
1388 tube_len = seg_len;
1389 i = inext;
1390 inext = inextnext;
1391 VEC_COPY (bi_0, bi_1);
1392 VEC_COPY (cut_0, cut_1);
1393 valid_cut_0 = valid_cut_1;
1394
1395 /* reflect the up vector in the bisecting plane */
1396 VEC_REFLECT (yup, yup, bi_0);
1397 }
1398 /* |-|-|-|-|-|-|-|-| END LOOP OVER SEGMENTS |-|-|-|-|-|-|-| */
1399
1400 free (mem_anchor);
1401
1402 }
1403
1404 /* =================== END OF FILE =============================== */
1405