home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / mesa-1.2.8 / src / clip.c < prev    next >
C/C++ Source or Header  |  1996-05-27  |  29KB  |  982 lines

  1. /* $Id: clip.c,v 1.17 1996/05/13 14:20:34 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  1.2
  6.  * Copyright (C) 1995-1996  Brian Paul  (brianp@ssec.wisc.edu)
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * Functions for clipping points, lines, and polygons against the view
  26.  * volume and user-defined clipping planes.
  27.  */
  28.  
  29.  
  30. /*
  31. $Log: clip.c,v $
  32.  * Revision 1.17  1996/05/13  14:20:34  brianp
  33.  * removed trivial-inside clip test from gl_viewclip_polygon()
  34.  *
  35.  * Revision 1.16  1995/12/30  17:13:05  brianp
  36.  * interpolate texture R,Q components per Bill Triggs
  37.  *
  38.  * Revision 1.15  1995/12/20  15:25:31  brianp
  39.  * changed VB color indexes to GLuint
  40.  *
  41.  * Revision 1.14  1995/10/14  17:41:29  brianp
  42.  * made glClipPlane display list-able
  43.  *
  44.  * Revision 1.13  1995/09/15  18:54:09  brianp
  45.  * changed INSIDE, OUTSIDE macros to fix Oleg Krivosheev's clipping problems
  46.  *
  47.  * Revision 1.12  1995/07/28  21:32:12  brianp
  48.  * fixed aux data interpolation bug in gl_viewclip_line()
  49.  *
  50.  * Revision 1.11  1995/07/24  20:34:16  brianp
  51.  * replaced memset() with MEMSET() and memcpy() with MEMCPY()
  52.  *
  53.  * Revision 1.10  1995/07/14  16:11:26  brianp
  54.  * tests for divide by zero added to gl_userclip_line()
  55.  *
  56.  * Revision 1.9  1995/06/02  13:59:16  brianp
  57.  * changed MAX_VERTICES to VB_SIZE
  58.  *
  59.  * Revision 1.8  1995/05/22  21:02:41  brianp
  60.  * Release 1.2
  61.  *
  62.  * Revision 1.7  1995/05/12  19:24:13  brianp
  63.  * replaced CC.Mode!=0 with INSIDE_BEGIN_END
  64.  *
  65.  * Revision 1.6  1995/03/24  15:30:41  brianp
  66.  * introduced VB
  67.  *
  68.  * Revision 1.5  1995/03/09  21:41:03  brianp
  69.  * new ModelViewInv matrix logic
  70.  *
  71.  * Revision 1.4  1995/03/09  20:07:46  brianp
  72.  * changed order of arguments in gl_transform_vector
  73.  *
  74.  * Revision 1.3  1995/03/08  19:01:11  brianp
  75.  * removed extra #include "clip.h"
  76.  *
  77.  * Revision 1.2  1995/03/04  19:29:44  brianp
  78.  * 1.1 beta revision
  79.  *
  80.  * Revision 1.1  1995/02/24  14:18:09  brianp
  81.  * Initial revision
  82.  *
  83.  */
  84.  
  85.  
  86. #include <string.h>
  87. #include "GL/gl.h"
  88. #include "clip.h"
  89. #include "context.h"
  90. #include "list.h"
  91. #include "macros.h"
  92. #include "vb.h"
  93. #include "xform.h"
  94.  
  95.  
  96.  
  97.  
  98. /* Linear interpolation between A and B: */
  99. #define LINTERP( T, A, B )   ( (A) + (T) * ( (B) - (A) ) )
  100.  
  101.  
  102. #define EYE_SPACE 1
  103. #define CLIP_SPACE 2
  104.  
  105. static GLuint Space;
  106.  
  107.  
  108.  
  109. /*
  110.  * This function is used to interpolate colors, indexes, and texture
  111.  * coordinates when clipping has to be done.  In general, we compute
  112.  *     aux[dst] = aux[in] + t * (aux[out] - aux[in])
  113.  * where aux is the quantity to be interpolated.
  114.  * Input:  dst - index of array position to store interpolated value
  115.  *         t - a value in [0,1]
  116.  *         in - index of array position corresponding to 'inside' vertex
  117.  *         out - index of array position corresponding to 'outside' vertex
  118.  */
  119. static void interpolate_aux( GLuint dst, GLfloat t, GLuint in, GLuint out )
  120. {
  121.    if (CC.ClipMask & CLIP_FCOLOR_BIT) {
  122.       VB.Fcolor[dst][0] = LINTERP( t, VB.Fcolor[in][0], VB.Fcolor[out][0] );
  123.       VB.Fcolor[dst][1] = LINTERP( t, VB.Fcolor[in][1], VB.Fcolor[out][1] );
  124.       VB.Fcolor[dst][2] = LINTERP( t, VB.Fcolor[in][2], VB.Fcolor[out][2] );
  125.       VB.Fcolor[dst][3] = LINTERP( t, VB.Fcolor[in][3], VB.Fcolor[out][3] );
  126.    }
  127.    else if (CC.ClipMask & CLIP_FINDEX_BIT) {
  128.       VB.Findex[dst] = (GLuint) (GLint) LINTERP( t, (GLfloat) VB.Findex[in],
  129.                                                  (GLfloat) VB.Findex[out] );
  130.    }
  131.  
  132.    if (CC.ClipMask & CLIP_BCOLOR_BIT) {
  133.       VB.Bcolor[dst][0] = LINTERP( t, VB.Bcolor[in][0], VB.Bcolor[out][0] );
  134.       VB.Bcolor[dst][1] = LINTERP( t, VB.Bcolor[in][1], VB.Bcolor[out][1] );
  135.       VB.Bcolor[dst][2] = LINTERP( t, VB.Bcolor[in][2], VB.Bcolor[out][2] );
  136.       VB.Bcolor[dst][3] = LINTERP( t, VB.Bcolor[in][3], VB.Bcolor[out][3] );
  137.    }
  138.    else if (CC.ClipMask & CLIP_BINDEX_BIT) {
  139.       VB.Bindex[dst] = (GLuint) (GLint) LINTERP( t, (GLfloat) VB.Bindex[in],
  140.                                                  (GLfloat) VB.Bindex[out] );
  141.    }
  142.  
  143.    if (CC.ClipMask & CLIP_TEXTURE_BIT) {
  144.       /* TODO: is more sophisticated texture coord interpolation needed?? */
  145.       if (Space==CLIP_SPACE) {
  146.      /* also interpolate eye Z component */
  147.      VB.Eye[dst][2] = LINTERP( t, VB.Eye[in][2], VB.Eye[out][2] );
  148.       }
  149.       VB.TexCoord[dst][0] = LINTERP(t,VB.TexCoord[in][0],VB.TexCoord[out][0]);
  150.       VB.TexCoord[dst][1] = LINTERP(t,VB.TexCoord[in][1],VB.TexCoord[out][1]);
  151.       VB.TexCoord[dst][2] = LINTERP(t,VB.TexCoord[in][2],VB.TexCoord[out][2]);
  152.       VB.TexCoord[dst][3] = LINTERP(t,VB.TexCoord[in][3],VB.TexCoord[out][3]);
  153.    }
  154.  
  155. }
  156.  
  157.  
  158.  
  159.  
  160. void gl_clipplane( GLenum plane, const float *equation )
  161. {
  162.    GLint p;
  163.  
  164.    p = (GLint) (plane - GL_CLIP_PLANE0);
  165.    if (p<0 || p>=MAX_CLIP_PLANES) {
  166.       gl_error( GL_INVALID_ENUM, "glClipPlane" );
  167.       return;
  168.    }
  169.  
  170.    /*
  171.     * The Equation is transformed by the transpose of the inverse of the
  172.     * current modelview matrix and stored in the resulting eye coordinates.
  173.     */
  174.    if (!CC.ModelViewInvValid) {
  175.       gl_compute_modelview_inverse();
  176.    }
  177.    gl_transform_vector( CC.Transform.ClipEquation[p], equation,
  178.                 CC.ModelViewInv );
  179. }
  180.  
  181.  
  182.  
  183. void glClipPlane( GLenum plane, const GLdouble *equation )
  184. {
  185.    GLfloat fequation[4];
  186.    fequation[0] = (GLfloat) equation[0];
  187.    fequation[1] = (GLfloat) equation[1];
  188.    fequation[2] = (GLfloat) equation[2];
  189.    fequation[3] = (GLfloat) equation[3];
  190.    if (CC.CompileFlag) {
  191.       gl_save_clipplane( plane, fequation );
  192.    }
  193.    if (CC.ExecuteFlag) {
  194.       gl_clipplane( plane, fequation );
  195.    }
  196. }
  197.  
  198.  
  199.  
  200. void glGetClipPlane( GLenum plane, GLdouble *equation )
  201. {
  202.    GLint p;
  203.  
  204.    if (INSIDE_BEGIN_END) {
  205.       gl_error( GL_INVALID_OPERATION, "glGetClipPlane" );
  206.       return;
  207.    }
  208.  
  209.    p = (GLint) (plane - GL_CLIP_PLANE0);
  210.    if (p<0 || p>=MAX_CLIP_PLANES) {
  211.       gl_error( GL_INVALID_ENUM, "glGetClipPlane" );
  212.       return;
  213.    }
  214.  
  215.    equation[0] = (GLdouble) CC.Transform.ClipEquation[p][0];
  216.    equation[1] = (GLdouble) CC.Transform.ClipEquation[p][1];
  217.    equation[2] = (GLdouble) CC.Transform.ClipEquation[p][2];
  218.    equation[3] = (GLdouble) CC.Transform.ClipEquation[p][3];
  219. }
  220.  
  221.  
  222.  
  223.  
  224. /**********************************************************************/
  225. /*                         View volume clipping.                      */
  226. /**********************************************************************/
  227.  
  228.  
  229. /*
  230.  * Clip a point against the view volume.
  231.  * Input:  v - vertex-vector describing the point to clip
  232.  * Return:  0 = outside view volume
  233.  *          1 = inside view volume
  234.  */
  235. GLuint gl_viewclip_point( const GLfloat v[] )
  236. {
  237.    if (   v[0] > v[3] || v[0] < -v[3]
  238.        || v[1] > v[3] || v[1] < -v[3]
  239.        || v[2] > v[3] || v[2] < -v[3] ) {
  240.       return 0;
  241.    }
  242.    else {
  243.       return 1;
  244.    }
  245. }
  246.  
  247.  
  248.  
  249.  
  250. /*
  251.  * Clip a line segment against the view volume defined by -w<=x,y,z<=w.
  252.  * Input:  i, j - indexes into VB.V* of endpoints of the line
  253.  * Return:  0 = line completely outside of view
  254.  *          1 = line is inside view.
  255.  */
  256. GLuint gl_viewclip_line( GLuint *i, GLuint *j )
  257. {
  258.    GLfloat t, dx, dy, dz, dw;
  259.    register GLuint ii, jj;
  260.  
  261.    Space = CLIP_SPACE;
  262.    ii = *i;
  263.    jj = *j;
  264.  
  265. /*
  266.  * We use 6 instances of this code to clip agains the 6 planes.
  267.  * For each plane, we define the OUTSIDE and COMPUTE_INTERSECTION
  268.  * macros apprpriately.
  269.  */
  270. #define GENERAL_CLIP                            \
  271.    if (OUTSIDE(ii)) {                                           \
  272.       if (OUTSIDE(jj)) {                                        \
  273.          /* both verts are outside ==> return 0 */            \
  274.          return 0;                                              \
  275.       }                                                         \
  276.       else {                                                    \
  277.          /* ii is outside, jj is inside ==> clip */             \
  278.      /* new vertex put in position VB.Free */            \
  279.          COMPUTE_INTERSECTION( VB.Free, jj, ii )                     \
  280.      if (CC.ClipMask)  interpolate_aux( VB.Free, t, jj, ii );    \
  281.      ii = VB.Free;                            \
  282.      VB.Free++;                            \
  283.      if (VB.Free==VB_SIZE)  VB.Free = 1;                \
  284.       }                                                         \
  285.    }                                                            \
  286.    else {                                                       \
  287.       if (OUTSIDE(jj)) {                                        \
  288.          /* ii is inside, jj is outside ==> clip */             \
  289.      /* new vertex put in position VB.Free */            \
  290.          COMPUTE_INTERSECTION( VB.Free, ii, jj );                    \
  291.      if (CC.ClipMask)  interpolate_aux( VB.Free, t, ii, jj );    \
  292.      jj = VB.Free;                            \
  293.      VB.Free++;                            \
  294.      if (VB.Free==VB_SIZE)  VB.Free = 1;                \
  295.       }                                                         \
  296.       /* else both verts are inside ==> do nothing */           \
  297.    }
  298.  
  299.  
  300. #define X(I)    VB.Clip[I][0]
  301. #define Y(I)    VB.Clip[I][1]
  302. #define Z(I)    VB.Clip[I][2]
  303. #define W(I)    VB.Clip[I][3]
  304.  
  305. /*
  306.  * Begin clipping
  307.  */
  308.  
  309.    /*** Clip against +X side ***/
  310. #define OUTSIDE(K)      (X(K) > W(K))
  311. #define COMPUTE_INTERSECTION( new, in, out )        \
  312.     dx = X(out) - X(in);                \
  313.     dw = W(out) - W(in);                \
  314.     t = (X(in) - W(in)) / (dw-dx);            \
  315.     X(new) = X(in) + t * dx;            \
  316.     Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  317.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  318.     W(new) = W(in) + t * dw;
  319.  
  320.    GENERAL_CLIP
  321.  
  322. #undef OUTSIDE
  323. #undef COMPUTE_INTERSECTION
  324.  
  325.  
  326.    /*** Clip against -X side ***/
  327. #define OUTSIDE(K)      (X(K) < -W(K))
  328. #define COMPUTE_INTERSECTION( new, in, out )        \
  329.     dx = X(out) - X(in);                \
  330.     dw = W(out) - W(in);                \
  331.         t = -(X(in) + W(in)) / (dw+dx);            \
  332.     X(new) = X(in) + t * dx;            \
  333.     Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  334.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  335.     W(new) = W(in) + t * dw;
  336.  
  337.    GENERAL_CLIP
  338.  
  339. #undef OUTSIDE
  340. #undef COMPUTE_INTERSECTION
  341.  
  342.  
  343.    /*** Clip against +Y side ***/
  344. #define OUTSIDE(K)      (Y(K) > W(K))
  345. #define COMPUTE_INTERSECTION( new, in, out )        \
  346.     dy = Y(out) - Y(in);                \
  347.     dw = W(out) - W(in);                \
  348.         t = (Y(in) - W(in)) / (dw-dy);            \
  349.     X(new) = X(in) + t * (X(out) - X(in));        \
  350.     Y(new) = Y(in) + t * dy;            \
  351.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  352.     W(new) = W(in) + t * dw;
  353.  
  354.    GENERAL_CLIP
  355.  
  356. #undef OUTSIDE
  357. #undef COMPUTE_INTERSECTION
  358.  
  359.  
  360.    /*** Clip against -Y side ***/
  361. #define OUTSIDE(K)      (Y(K) < -W(K))
  362. #define COMPUTE_INTERSECTION( new, in, out )        \
  363.         dy = Y(out) - Y(in);                \
  364.         dw = W(out) - W(in);                \
  365.         t = -(Y(in) + W(in)) / (dw+dy);            \
  366.         X(new) = X(in) + t * (X(out) - X(in));        \
  367.     Y(new) = Y(in) + t * dy;            \
  368.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  369.     W(new) = W(in) + t * dw;
  370.  
  371.    GENERAL_CLIP
  372.  
  373. #undef OUTSIDE
  374. #undef COMPUTE_INTERSECTION
  375.  
  376.  
  377.    /*** Clip against +Z side ***/
  378. #define OUTSIDE(K)      (Z(K) > W(K))
  379. #define COMPUTE_INTERSECTION( new, in, out )        \
  380.         dz = Z(out) - Z(in);                \
  381.         dw = W(out) - W(in);                \
  382.         t = (Z(in) - W(in)) / (dw-dz);            \
  383.         X(new) = X(in) + t * (X(out) - X(in));        \
  384.         Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  385.     Z(new) = Z(in) + t * dz;            \
  386.     W(new) = W(in) + t * dw;
  387.  
  388.    GENERAL_CLIP
  389.  
  390. #undef OUTSIDE
  391. #undef COMPUTE_INTERSECTION
  392.  
  393.  
  394.    /*** Clip against -Z side ***/
  395. #define OUTSIDE(K)      (Z(K) < -W(K))
  396. #define COMPUTE_INTERSECTION( new, in, out )        \
  397.         dz = Z(out) - Z(in);                \
  398.         dw = W(out) - W(in);                \
  399.         t = -(Z(in) + W(in)) / (dw+dz);            \
  400.         X(new) = X(in) + t * (X(out) - X(in));        \
  401.         Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  402.     Z(new) = Z(in) + t * dz;            \
  403.     W(new) = W(in) + t * dw;
  404.  
  405.    GENERAL_CLIP
  406.  
  407. #undef OUTSIDE
  408. #undef COMPUTE_INTERSECTION
  409.  
  410. #undef GENERAL_CLIP
  411.  
  412.    *i = ii;
  413.    *j = jj;
  414.    return 1;
  415. }
  416.  
  417.  
  418.  
  419.  
  420. /*
  421.  * Clip a polygon against the view volume defined by -w<=x,y,z<=w.
  422.  * Input:  n - number of vertices in input polygon.
  423.  *         vlist - list of indexes into VB.V* of polygon to clip.
  424.  * Output:  vlist - modified list of vertex indexes
  425.  * Return:  number of vertices in resulting polygon
  426.  */
  427. GLuint gl_viewclip_polygon( GLuint n, GLuint vlist[] )
  428.  
  429. {
  430.    GLuint previ, prevj;
  431.    GLuint curri, currj;
  432.    GLuint vlist2[VB_MAX];
  433.    GLuint n2;
  434.    GLfloat dx, dy, dz, dw, t;
  435.    GLuint incount, i;
  436.  
  437.    Space = CLIP_SPACE;
  438.  
  439. /*
  440.  * We use 6 instances of this code to implement clipping against the
  441.  * 6 sides of the view volume.  Prior to each we define the macros:
  442.  *    INLIST = array which lists input vertices
  443.  *    OUTLIST = array which lists output vertices
  444.  *    INCOUNT = variable which is the number of vertices in INLIST[]
  445.  *    OUTCOUNT = variable which is the number of vertices in OUTLIST[]
  446.  *    INSIDE(J) = test if vertex[J] is inside the view volume
  447.  *    COMPUTE_INTERSECTION(inv,outv,newv) = compute intersection of line
  448.  *              from inv[] to outv[] with the clipping plane and store
  449.  *              the result in newv[]
  450.  */
  451.  
  452. #define GENERAL_CLIP                                                    \
  453.    if (INCOUNT<3)  return 0;                        \
  454.    previ = INCOUNT-1;        /* let previous = last vertex */    \
  455.    prevj = INLIST[previ];                        \
  456.    OUTCOUNT = 0;                                                        \
  457.    for (curri=0;curri<INCOUNT;curri++) {                \
  458.       currj = INLIST[curri];                        \
  459.       if (INSIDE(currj)) {                        \
  460.          if (INSIDE(prevj)) {                        \
  461.             /* both verts are inside ==> copy current to outlist */     \
  462.         OUTLIST[OUTCOUNT] = currj;                    \
  463.         OUTCOUNT++;                            \
  464.          }                                                              \
  465.          else {                                                         \
  466.             /* current is inside and previous is outside ==> clip */    \
  467.         COMPUTE_INTERSECTION( VB.Clip[currj], VB.Clip[prevj],    \
  468.                      VB.Clip[VB.Free] )        \
  469.         /* interpolate aux info using the value of t */        \
  470.         if (CC.ClipMask)  interpolate_aux( VB.Free, t, currj, prevj ); \
  471.         VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];        \
  472.         OUTLIST[OUTCOUNT] = VB.Free;                \
  473.         VB.Free++;                            \
  474.         if (VB.Free==VB_SIZE)   VB.Free = 1;            \
  475.         OUTCOUNT++;                            \
  476.         /* Output current */                    \
  477.         OUTLIST[OUTCOUNT] = currj;                    \
  478.         OUTCOUNT++;                            \
  479.          }                                                              \
  480.       }                                                                 \
  481.       else {                                                            \
  482.          if (INSIDE(prevj)) {                                           \
  483.             /* current is outside and previous is inside ==> clip */    \
  484.         COMPUTE_INTERSECTION( VB.Clip[prevj], VB.Clip[currj],    \
  485.                     VB.Clip[VB.Free] )        \
  486.         /* interpolate aux info using the value of t */        \
  487.         if (CC.ClipMask)  interpolate_aux( VB.Free, t, prevj, currj ); \
  488.         VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];        \
  489.         OUTLIST[OUTCOUNT] = VB.Free;                \
  490.         VB.Free++;                            \
  491.         if (VB.Free==VB_SIZE)   VB.Free = 1;            \
  492.         OUTCOUNT++;                            \
  493.          }                                                              \
  494.          /* else both verts are outside ==> do nothing */               \
  495.       }                                                                 \
  496.       /* let previous = current */                    \
  497.       previ = curri;                            \
  498.       prevj = currj;                            \
  499.    }
  500.  
  501.  
  502. /*
  503.  * Clip against +X
  504.  */
  505. #define INCOUNT n
  506. #define OUTCOUNT n2
  507. #define INLIST vlist
  508. #define OUTLIST vlist2
  509. #define INSIDE(J)      ( VB.Clip[J][0] <= VB.Clip[J][3] )
  510.  
  511. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  512.         dx = outv[0] - inv[0];                \
  513.         dw = outv[3] - inv[3];                \
  514.         t = (inv[0]-inv[3]) / (dw-dx);            \
  515.     newv[0] = inv[0] + t * dx;            \
  516.     newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  517.     newv[2] = inv[2] + t * (outv[2]-inv[2]);     \
  518.     newv[3] = inv[3] + t * dw;
  519.  
  520.    GENERAL_CLIP
  521.  
  522. #undef INCOUNT
  523. #undef OUTCOUNT
  524. #undef INLIST
  525. #undef OUTLIST
  526. #undef INSIDE
  527. #undef COMPUTE_INTERSECTION
  528.  
  529.  
  530. /*
  531.  * Clip against -X
  532.  */
  533. #define INCOUNT n2
  534. #define OUTCOUNT n
  535. #define INLIST vlist2
  536. #define OUTLIST vlist
  537. #define INSIDE(J)       (VB.Clip[J][0] >= -VB.Clip[J][3])
  538.  
  539. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  540.         dx = outv[0]-inv[0];                          \
  541.         dw = outv[3]-inv[3];                          \
  542.         t = -(inv[0]+inv[3]) / (dw+dx);               \
  543.         newv[0] = inv[0] + t * dx;                    \
  544.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  545.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  546.         newv[3] = inv[3] + t * dw;
  547.  
  548.    GENERAL_CLIP
  549.  
  550. #undef INCOUNT
  551. #undef OUTCOUNT
  552. #undef INLIST
  553. #undef OUTLIST
  554. #undef INSIDE
  555. #undef COMPUTE_INTERSECTION
  556.  
  557.  
  558. /*
  559.  * Clip against +Y
  560.  */
  561. #define INCOUNT n
  562. #define OUTCOUNT n2
  563. #define INLIST vlist
  564. #define OUTLIST vlist2
  565. #define INSIDE(J)       (VB.Clip[J][1] <= VB.Clip[J][3])
  566. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  567.         dy = outv[1]-inv[1];                          \
  568.         dw = outv[3]-inv[3];                          \
  569.         t = (inv[1]-inv[3]) / (dw-dy);                \
  570.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  571.         newv[1] = inv[1] + t * dy;            \
  572.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  573.         newv[3] = inv[3] + t * dw;
  574.  
  575.    GENERAL_CLIP
  576.  
  577. #undef INCOUNT
  578. #undef OUTCOUNT
  579. #undef INLIST
  580. #undef OUTLIST
  581. #undef INSIDE
  582. #undef COMPUTE_INTERSECTION
  583.  
  584.  
  585. /*
  586.  * Clip against -Y
  587.  */
  588. #define INCOUNT n2
  589. #define OUTCOUNT n
  590. #define INLIST vlist2
  591. #define OUTLIST vlist
  592. #define INSIDE(J)       (VB.Clip[J][1] >= -VB.Clip[J][3])
  593. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  594.         dy = outv[1]-inv[1];                          \
  595.         dw = outv[3]-inv[3];                          \
  596.         t = -(inv[1]+inv[3]) / (dw+dy);               \
  597.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  598.         newv[1] = inv[1] + t * dy;                    \
  599.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  600.         newv[3] = inv[3] + t * dw;
  601.  
  602.    GENERAL_CLIP
  603.  
  604. #undef INCOUNT
  605. #undef OUTCOUNT
  606. #undef INLIST
  607. #undef OUTLIST
  608. #undef INSIDE
  609. #undef COMPUTE_INTERSECTION
  610.  
  611.  
  612.  
  613. /*
  614.  * Clip against +Z
  615.  */
  616. #define INCOUNT n
  617. #define OUTCOUNT n2
  618. #define INLIST vlist
  619. #define OUTLIST vlist2
  620. #define INSIDE(J)       (VB.Clip[J][2] <= VB.Clip[J][3])
  621. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  622.         dz = outv[2]-inv[2];                          \
  623.         dw = outv[3]-inv[3];                          \
  624.         t = (inv[2]-inv[3]) / (dw-dz);                \
  625.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  626.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  627.         newv[2] = inv[2] + t * dz;                    \
  628.         newv[3] = inv[3] + t * dw;
  629.  
  630.    GENERAL_CLIP
  631.  
  632. #undef INCOUNT
  633. #undef OUTCOUNT
  634. #undef INLIST
  635. #undef OUTLIST
  636. #undef INSIDE
  637. #undef COMPUTE_INTERSECTION
  638.  
  639.  
  640. /*
  641.  * Clip against -Z
  642.  */
  643. #define INCOUNT n2
  644. #define OUTCOUNT n
  645. #define INLIST vlist2
  646. #define OUTLIST vlist
  647. #define INSIDE(J)       (VB.Clip[J][2] >= -VB.Clip[J][3])
  648. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  649.         dz = outv[2]-inv[2];                          \
  650.         dw = outv[3]-inv[3];                          \
  651.         t = -(inv[2]+inv[3]) / (dw+dz);               \
  652.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  653.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  654.         newv[2] = inv[2] + t * dz;                    \
  655.         newv[3] = inv[3] + t * dw;
  656.  
  657.    GENERAL_CLIP
  658.  
  659. #undef INCOUNT
  660. #undef INLIST
  661. #undef OUTLIST
  662. #undef INSIDE
  663. #undef COMPUTE_INTERSECTION
  664.  
  665.    /* 'OUTCOUNT' clipped vertices are now back in v[] */
  666.    return OUTCOUNT;
  667.  
  668. #undef GENERAL_CLIP
  669. #undef OUTCOUNT
  670. }
  671.  
  672.  
  673.  
  674.  
  675. /**********************************************************************/
  676. /*         Clipping against user-defined clipping planes.             */
  677. /**********************************************************************/
  678.  
  679.  
  680.  
  681. /*
  682.  * If the dot product of the eye coordinates of a vertex with the
  683.  * stored plane equation components is positive or zero, the vertex
  684.  * is in with respect to that clipping plane, otherwise it is out.
  685.  */
  686.  
  687.  
  688.  
  689. /*
  690.  * Clip a point against the user clipping planes.
  691.  * Input:  v - vertex-vector describing the point to clip.
  692.  * Return:  0 = point was clipped
  693.  *          1 = point not clipped
  694.  */
  695. GLuint gl_userclip_point( const GLfloat v[] )
  696. {
  697.    GLuint p;
  698.  
  699.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  700.       if (CC.Transform.ClipEnabled[p]) {
  701.      GLfloat dot = v[0] * CC.Transform.ClipEquation[p][0]
  702.              + v[1] * CC.Transform.ClipEquation[p][1]
  703.              + v[2] * CC.Transform.ClipEquation[p][2]
  704.              + v[3] * CC.Transform.ClipEquation[p][3];
  705.          if (dot < 0.0F) {
  706.             return 0;
  707.          }
  708.       }
  709.    }
  710.  
  711.    return 1;
  712. }
  713.  
  714.  
  715. #define MAGIC_NUMBER -0.8e-03F
  716.  
  717.  
  718. /* Test if VB.Eye[J] is inside the clipping plane defined by A,B,C,D */
  719. #define INSIDE( J, A, B, C, D )                   \
  720.    ( (VB.Eye[J][0] * A + VB.Eye[J][1] * B            \
  721.     + VB.Eye[J][2] * C + VB.Eye[J][3] * D) >= MAGIC_NUMBER )
  722.  
  723.  
  724. /* Test if VB.Eye[J] is outside the clipping plane defined by A,B,C,D */
  725. #define OUTSIDE( J, A, B, C, D )                   \
  726.    ( (VB.Eye[J][0] * A + VB.Eye[J][1] * B            \
  727.     + VB.Eye[J][2] * C + VB.Eye[J][3] * D) < MAGIC_NUMBER )
  728.  
  729.  
  730. /*
  731.  * Clip a line against the user clipping planes.
  732.  * Input:  i, j - indexes into VB.V*[] of endpoints
  733.  * Output:  i, j - indexes into VB.V*[] of (possibly clipped) endpoints
  734.  * Return:  0 = line completely clipped
  735.  *          1 = line is visible
  736.  */
  737. GLuint gl_userclip_line( GLuint *i, GLuint *j )
  738. {
  739.    GLuint p, ii, jj;
  740.  
  741.    Space = EYE_SPACE;
  742.  
  743.    ii = *i;
  744.    jj = *j;
  745.  
  746.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  747.       if (CC.Transform.ClipEnabled[p]) {
  748.      register GLfloat a, b, c, d;
  749.      a = CC.Transform.ClipEquation[p][0];
  750.      b = CC.Transform.ClipEquation[p][1];
  751.      c = CC.Transform.ClipEquation[p][2];
  752.      d = CC.Transform.ClipEquation[p][3];
  753.  
  754.          if (OUTSIDE( ii, a,b,c,d  )) {
  755.             if (OUTSIDE( jj, a,b,c,d )) {
  756.                /* ii and jj outside ==> quit */
  757.                return 0;
  758.             }
  759.             else {
  760.                /* ii is outside, jj is inside ==> clip */
  761.                GLfloat dx, dy, dz, dw, t, denom;
  762.                dx = VB.Eye[ii][0] - VB.Eye[jj][0];
  763.                dy = VB.Eye[ii][1] - VB.Eye[jj][1];
  764.                dz = VB.Eye[ii][2] - VB.Eye[jj][2];
  765.                dw = VB.Eye[ii][3] - VB.Eye[jj][3];
  766.            denom = dx*a + dy*b + dz*c + dw*d;
  767.            if (denom==0.0) {
  768.           t = 0.0;
  769.            }
  770.            else {
  771.           t = -(VB.Eye[jj][0]*a+VB.Eye[jj][1]*b
  772.                +VB.Eye[jj][2]*c+VB.Eye[jj][3]*d) / denom;
  773.                   if (t>1.0F)  t = 1.0F;
  774.            }
  775.            VB.Eye[VB.Free][0] = VB.Eye[jj][0] + t * dx;
  776.            VB.Eye[VB.Free][1] = VB.Eye[jj][1] + t * dy;
  777.            VB.Eye[VB.Free][2] = VB.Eye[jj][2] + t * dz;
  778.            VB.Eye[VB.Free][3] = VB.Eye[jj][3] + t * dw;
  779.  
  780.            /* Interpolate colors, indexes, and/or texture coords */
  781.            if (CC.ClipMask)  interpolate_aux( VB.Free, t, jj, ii );
  782.  
  783.            ii = VB.Free;
  784.            VB.Free++;
  785.            if (VB.Free==VB_SIZE)   VB.Free = 1;
  786.             }
  787.          }
  788.          else {
  789.             if (OUTSIDE( jj, a,b,c,d )) {
  790.                /* ii is inside, jj is outside ==> clip */
  791.                GLfloat dx, dy, dz, dw, t, denom;
  792.                dx = VB.Eye[jj][0] - VB.Eye[ii][0];
  793.                dy = VB.Eye[jj][1] - VB.Eye[ii][1];
  794.                dz = VB.Eye[jj][2] - VB.Eye[ii][2];
  795.                dw = VB.Eye[jj][3] - VB.Eye[ii][3];
  796.            denom = dx*a + dy*b + dz*c + dw*d;
  797.            if (denom==0.0) {
  798.           t = 0.0;
  799.            }
  800.            else {
  801.           t = -(VB.Eye[ii][0]*a+VB.Eye[ii][1]*b
  802.                +VB.Eye[ii][2]*c+VB.Eye[ii][3]*d) / denom;
  803.                   if (t>1.0F)  t = 1.0F;
  804.            }
  805.            VB.Eye[VB.Free][0] = VB.Eye[ii][0] + t * dx;
  806.            VB.Eye[VB.Free][1] = VB.Eye[ii][1] + t * dy;
  807.            VB.Eye[VB.Free][2] = VB.Eye[ii][2] + t * dz;
  808.            VB.Eye[VB.Free][3] = VB.Eye[ii][3] + t * dw;
  809.  
  810.            /* Interpolate colors, indexes, and/or texture coords */
  811.            if (CC.ClipMask)  interpolate_aux( VB.Free, t, ii, jj );
  812.  
  813.            jj = VB.Free;
  814.            VB.Free++;
  815.            if (VB.Free==VB_SIZE)   VB.Free = 1;
  816.             }
  817.             else {
  818.                /* ii and jj inside ==> do nothing */
  819.             }
  820.          }
  821.       }
  822.    }
  823.  
  824.    *i = ii;
  825.    *j = jj;
  826.    return 1;
  827. }
  828.  
  829.  
  830.  
  831.  
  832. /*
  833.  * Clip a polygon against the user clipping planes defined in eye coordinates.
  834.  * Input:  n - number of vertices.
  835.  *         vlist - list of vertices in input polygon.
  836.  * Output:  vlist - list of vertices in output polygon.
  837.  * Return:  number of vertices after clipping.
  838.  */
  839. GLuint gl_userclip_polygon( GLuint n, GLuint vlist[] )
  840. {
  841.    GLuint vlist2[VB_MAX];
  842.    GLuint *inlist, *outlist;
  843.    GLuint incount, outcount;
  844.    GLuint curri, currj;
  845.    GLuint previ, prevj;
  846.    GLuint p;
  847.  
  848.    Space = EYE_SPACE;
  849.  
  850.    /* initialize input vertex list */
  851.    incount = n;
  852.    inlist = vlist;
  853.    outlist = vlist2;
  854.  
  855.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  856.       if (CC.Transform.ClipEnabled[p]) {
  857.      register float a = CC.Transform.ClipEquation[p][0];
  858.      register float b = CC.Transform.ClipEquation[p][1];
  859.      register float c = CC.Transform.ClipEquation[p][2];
  860.      register float d = CC.Transform.ClipEquation[p][3];
  861.  
  862.      if (incount<3)  return 0;
  863.  
  864.      /* initialize prev to be last in the input list */
  865.      previ = incount - 1;
  866.      prevj = inlist[previ];
  867.  
  868.          outcount = 0;
  869.  
  870.          for (curri=0;curri<incount;curri++) {
  871.         currj = inlist[curri];
  872.  
  873.             if (INSIDE(currj, a,b,c,d)) {
  874.                if (INSIDE(prevj, a,b,c,d)) {
  875.                   /* both verts are inside ==> copy current to outlist */
  876.           outlist[outcount++] = currj;
  877.                }
  878.                else {
  879.                   /* current is inside and previous is outside ==> clip */
  880.                   GLfloat dx, dy, dz, dw, t, denom;
  881.           /* compute t */
  882.           dx = VB.Eye[prevj][0] - VB.Eye[currj][0];
  883.           dy = VB.Eye[prevj][1] - VB.Eye[currj][1];
  884.           dz = VB.Eye[prevj][2] - VB.Eye[currj][2];
  885.           dw = VB.Eye[prevj][3] - VB.Eye[currj][3];
  886.           denom = dx*a + dy*b + dz*c + dw*d;
  887.           if (denom==0.0) {
  888.              t = 0.0;
  889.           }
  890.           else {
  891.              t = -(VB.Eye[currj][0]*a+VB.Eye[currj][1]*b
  892.                +VB.Eye[currj][2]*c+VB.Eye[currj][3]*d) / denom;
  893.                      if (t>1.0F) {
  894.                         /*printf("t1=%g\n", t);*/
  895.                         t = 1.0F;
  896.                      }
  897.           }
  898.           /* interpolate new vertex position */
  899.           VB.Eye[VB.Free][0] = VB.Eye[currj][0] + t*dx;
  900.           VB.Eye[VB.Free][1] = VB.Eye[currj][1] + t*dy;
  901.           VB.Eye[VB.Free][2] = VB.Eye[currj][2] + t*dz;
  902.           VB.Eye[VB.Free][3] = VB.Eye[currj][3] + t*dw;
  903.  
  904.           /* interpolate color, index, and/or texture coord */
  905.           if (CC.ClipMask) interpolate_aux( VB.Free, t, currj, prevj);
  906.           VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
  907.  
  908.           /* output new vertex */
  909.           outlist[outcount++] = VB.Free;
  910.           VB.Free++;
  911.           if (VB.Free==VB_SIZE)   VB.Free = 1;
  912.           /* output current vertex */
  913.           outlist[outcount++] = currj;
  914.                }
  915.             }
  916.             else {
  917.                if (INSIDE(prevj, a,b,c,d)) {
  918.                   /* current is outside and previous is inside ==> clip */
  919.                   GLfloat dx, dy, dz, dw, t, denom;
  920.           /* compute t */
  921.                   dx = VB.Eye[currj][0]-VB.Eye[prevj][0];
  922.                   dy = VB.Eye[currj][1]-VB.Eye[prevj][1];
  923.                   dz = VB.Eye[currj][2]-VB.Eye[prevj][2];
  924.                   dw = VB.Eye[currj][3]-VB.Eye[prevj][3];
  925.           denom = dx*a + dy*b + dz*c + dw*d;
  926.           if (denom==0.0) {
  927.              t = 0.0;
  928.           }
  929.           else {
  930.              t = -(VB.Eye[prevj][0]*a+VB.Eye[prevj][1]*b
  931.                +VB.Eye[prevj][2]*c+VB.Eye[prevj][3]*d) / denom;
  932.                      if (t>1.0F) {
  933.                         /*printf("t2=%g\n", t);*/
  934.                         t = 1.0F;
  935.                      }
  936.           }
  937.           /* interpolate new vertex position */
  938.           VB.Eye[VB.Free][0] = VB.Eye[prevj][0] + t*dx;
  939.           VB.Eye[VB.Free][1] = VB.Eye[prevj][1] + t*dy;
  940.           VB.Eye[VB.Free][2] = VB.Eye[prevj][2] + t*dz;
  941.           VB.Eye[VB.Free][3] = VB.Eye[prevj][3] + t*dw;
  942.  
  943.           /* interpolate color, index, and/or texture coord */
  944.           if (CC.ClipMask) interpolate_aux( VB.Free, t, prevj, currj);
  945.           VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
  946.  
  947.           /* output new vertex */
  948.           outlist[outcount++] = VB.Free;
  949.           VB.Free++;
  950.           if (VB.Free==VB_SIZE)   VB.Free = 1;
  951.            }
  952.                /* else  both verts are outside ==> do nothing */
  953.             }
  954.  
  955.         previ = curri;
  956.         prevj = currj;
  957.  
  958.          }  /* for i */
  959.  
  960.          /* swap inv and outv pointers */
  961.          {
  962.             GLuint *tmp;
  963.             tmp = inlist;
  964.             inlist = outlist;
  965.             outlist = tmp;
  966.             incount = outcount;
  967.          }
  968.  
  969.       } /* if */
  970.    } /* for p */
  971.  
  972.    /* outlist points to the list of vertices resulting from the last */
  973.    /* clipping.  If outlist == vlist2 then we have to copy the vertices */
  974.    /* back to vlist */
  975.    if (outlist!=vlist2) {
  976.       MEMCPY( vlist, vlist2, outcount * sizeof(GLuint) );
  977.    }
  978.  
  979.    return outcount;
  980. }
  981.  
  982.