ex_cut_round.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:48k
源码类别:

GIS编程

开发平台:

Visual C++

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