home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / System / Mesa-3.1 / src / vbrender.c < prev    next >
C/C++ Source or Header  |  2000-01-07  |  19KB  |  724 lines

  1. /* $Id: vbrender.c,v 1.10.2.5 1999/12/16 12:53:24 keithw Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  3.1
  6.  * 
  7.  * Copyright (C) 1999  Brian Paul   All Rights Reserved.
  8.  * 
  9.  * Permission is hereby granted, free of charge, to any person obtaining a
  10.  * copy of this software and associated documentation files (the "Software"),
  11.  * to deal in the Software without restriction, including without limitation
  12.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13.  * and/or sell copies of the Software, and to permit persons to whom the
  14.  * Software is furnished to do so, subject to the following conditions:
  15.  * 
  16.  * The above copyright notice and this permission notice shall be included
  17.  * in all copies or substantial portions of the Software.
  18.  * 
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  22.  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  23.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  24.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Render points, lines, and polygons.  The only entry point to this
  30.  * file is the gl_render_vb() function.  This function is called after
  31.  * the vertex buffer has filled up or a state change has occurred.
  32.  *
  33.  * This file basically only makes calls to the clipping functions and
  34.  * the point, line and triangle rasterizers via the function pointers.
  35.  *    context->Driver.PointsFunc()
  36.  *    context->Driver.LineFunc()
  37.  *    context->Driver.TriangleFunc()
  38.  */
  39.  
  40.  
  41. #ifdef PC_HEADER
  42. #include "all.h"
  43. #else
  44. #ifndef XFree86Server
  45. #include <stdio.h>
  46. #else
  47. #include "GL/xf86glx.h"
  48. #endif
  49. #include "clip.h"
  50. #include "context.h"
  51. #include "light.h"
  52. #include "lines.h"
  53. #include "macros.h"
  54. #include "matrix.h"
  55. #include "pb.h"
  56. #include "points.h"
  57. #include "pipeline.h"
  58. #include "stages.h"
  59. #include "types.h"
  60. #include "vb.h"
  61. #include "vbcull.h"
  62. #include "vbrender.h"
  63. #include "vbindirect.h"
  64. #include "xform.h"
  65. #endif
  66.  
  67.  
  68. /*
  69.  * This file implements rendering of points, lines and polygons defined by
  70.  * vertices in the vertex buffer.
  71.  */
  72.  
  73. /*
  74.  * Render a line segment from VB[v1] to VB[v2] when either one or both
  75.  * endpoints must be clipped.
  76.  */
  77. void gl_render_clipped_line( GLcontext *ctx, GLuint v1, GLuint v2 )
  78. {
  79.    GLuint pv = v2;
  80.    struct vertex_buffer *VB = ctx->VB;
  81.    GLubyte mask = (GLubyte) (VB->ClipMask[v1] | VB->ClipMask[v2]);
  82. /*     GLubyte andmask = VB->ClipMask[v1] & VB->ClipMask[v2]; */
  83.  
  84.    if ((ctx->line_clip_tab[VB->ClipPtr->size])( VB, &v1, &v2, mask ))
  85.       ctx->Driver.LineFunc( ctx, v1, v2, pv );
  86. }
  87.  
  88. static INLINE void gl_render_clipped_line2( GLcontext *ctx, 
  89.                         GLuint v1, GLuint v2 )
  90. {
  91.    GLuint pv = v2;
  92.    struct vertex_buffer *VB = ctx->VB;
  93.    GLubyte mask = (GLubyte) (VB->ClipMask[v1] | VB->ClipMask[v2]);
  94.  
  95.    if (!mask || (ctx->line_clip_tab[VB->ClipPtr->size])( VB, &v1, &v2, mask ))
  96.       ctx->Driver.LineFunc( ctx, v1, v2, pv );
  97. }
  98.  
  99.  
  100.  
  101. /*
  102.  * Compute Z offsets for a polygon with plane defined by (A,B,C,D)
  103.  * D is not needed.
  104.  */
  105. static void offset_polygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c )
  106. {
  107.    GLfloat ac, bc, m;
  108.    GLfloat offset;
  109.  
  110.    if (c<0.001F && c>-0.001F) {
  111.       /* to prevent underflow problems */
  112.       offset = 0.0F;
  113.    }
  114.    else {
  115.       ac = a / c;
  116.       bc = b / c;
  117.       if (ac<0.0F)  ac = -ac;
  118.       if (bc<0.0F)  bc = -bc;
  119.       m = MAX2( ac, bc );
  120.       /* m = sqrt( ac*ac + bc*bc ); */
  121.  
  122.       offset = m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits;
  123.    }
  124.  
  125.    ctx->PointZoffset   = ctx->Polygon.OffsetPoint ? offset : 0.0F;
  126.    ctx->LineZoffset    = ctx->Polygon.OffsetLine  ? offset : 0.0F;
  127.    ctx->PolygonZoffset = ctx->Polygon.OffsetFill  ? offset : 0.0F;
  128. }
  129.  
  130. #define FLUSH_PRIM(prim)            \
  131. do {                        \
  132.    if (ctx->PB->primitive != prim) {        \
  133.       gl_reduced_prim_change( ctx, prim );        \
  134.    }                        \
  135. } while(0)
  136.  
  137.  
  138. /*
  139.  * When glPolygonMode() is used to specify that the front/back rendering
  140.  * mode for polygons is not GL_FILL we end up calling this function.
  141.  */
  142. static void unfilled_polygon( GLcontext *ctx,
  143.                               GLuint n, GLuint vlist[],
  144.                               GLuint pv, GLuint facing )
  145. {
  146.    GLenum mode = facing ? ctx->Polygon.BackMode : ctx->Polygon.FrontMode;
  147.    struct vertex_buffer *VB = ctx->VB;
  148.    GLubyte *edge_ptr = (GLubyte *)VB->EdgeFlagPtr->data;
  149.  
  150.    FLUSH_PRIM(mode);
  151.  
  152.    if (mode==GL_POINT) {
  153.       GLuint i, j;
  154.       for (i=0;i<n;i++) {
  155.          j = vlist[i];
  156.          if (edge_ptr[j] & 0x3) {
  157.         edge_ptr[j] &= ~0x3;
  158.             (*ctx->Driver.PointsFunc)( ctx, j, j );
  159.          }
  160.       }
  161.    }
  162.    else if (mode==GL_LINE) {
  163.       GLuint i, j0, j1;
  164.  
  165.       /* draw the edges */
  166.       for (i=0;i<n-1;i++) {
  167.      j0 = vlist[i];
  168.      j1 = vlist[i+1];
  169.     
  170.      if (edge_ptr[j0] & 0x1) {
  171.         edge_ptr[j0] &= ~1;
  172.             (*ctx->Driver.LineFunc)( ctx, j0, j1, pv );
  173.          }
  174.       }
  175.       
  176.       /* last edge is special */
  177.       j0 = vlist[i];
  178.       j1 = vlist[0];
  179.  
  180.       if (edge_ptr[j0] & 0x2) {
  181.      edge_ptr[j0] &= ~2;
  182.      (*ctx->Driver.LineFunc)( ctx, j0, j1, pv );
  183.       }
  184.    }
  185.    else {
  186.       /* Fill the polygon */
  187.       GLuint j0, i;
  188.       j0 = vlist[0];
  189.       for (i=2;i<n;i++) {
  190.          (*ctx->Driver.TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv );
  191.       }
  192.    }
  193. }
  194.  
  195.  
  196.  
  197.  
  198. /*
  199.  * Render a polygon in which at least one vertex has to be clipped.
  200.  * Input:  n - number of vertices
  201.  *         vlist - list of vertices in the polygon.
  202.  *                 CCW order = front facing.
  203.  */
  204. void gl_render_clipped_triangle( GLcontext *ctx, GLuint n, GLuint vlist[], 
  205.                  GLuint pv )
  206. {
  207.    struct vertex_buffer *VB = ctx->VB;
  208.    GLubyte mask = 0;
  209.    GLuint i;
  210.  
  211.    for (i = 0 ; i < n ; i++) 
  212.       mask |= VB->ClipMask[vlist[i]];
  213.  
  214.    n = (ctx->poly_clip_tab[VB->ClipPtr->size])( VB, n, vlist, mask );
  215.  
  216.    for (i=2;i<n;i++) 
  217.       ctx->TriangleFunc( ctx, *vlist, vlist[i-1], vlist[i], pv ); 
  218. }
  219.  
  220.  
  221. static INLINE void gl_render_clipped_triangle2( GLcontext *ctx, 
  222.                         GLuint v1, GLuint v2, GLuint v3,
  223.                         GLuint pv )
  224. {
  225.    struct vertex_buffer *VB = ctx->VB;
  226.    GLubyte mask = (GLubyte) (VB->ClipMask[v1] | VB->ClipMask[v2] | VB->ClipMask[v3]);
  227.    GLuint vlist[VB_MAX_CLIPPED_VERTS];
  228.    GLuint i, n;
  229.  
  230.    if (!mask) {
  231.       ctx->TriangleFunc( ctx, v1, v2, v3, pv ); 
  232.       return;
  233.    }
  234.  
  235.    if (CLIP_ALL_BITS & VB->ClipMask[v1] & VB->ClipMask[v2] & VB->ClipMask[v3]) 
  236.       return;
  237.  
  238.    ASSIGN_3V(vlist, v1, v2, v3 );
  239.    n = (ctx->poly_clip_tab[VB->ClipPtr->size])( VB, 3, vlist, mask );
  240.       
  241.    for (i=2;i<n;i++) 
  242.       ctx->TriangleFunc( ctx, *vlist, vlist[i-1], vlist[i], pv ); 
  243. }
  244.  
  245.  
  246. /* Implements triangle_rendering when (IndirectTriangles & DD_SW_SETUP)
  247.  * is non-zero.
  248.  */
  249. static void render_triangle( GLcontext *ctx,
  250.                              GLuint v0, GLuint v1, GLuint v2, GLuint pv )
  251. {
  252.    struct vertex_buffer *VB = ctx->VB;
  253.    GLfloat (*win)[4] = VB->Win.data;
  254.    GLfloat ex = win[v1][0] - win[v0][0];
  255.    GLfloat ey = win[v1][1] - win[v0][1];
  256.    GLfloat fx = win[v2][0] - win[v0][0];
  257.    GLfloat fy = win[v2][1] - win[v0][1];
  258.    GLfloat c = ex*fy-ey*fx;
  259.    GLuint facing;
  260.    GLuint tricaps;
  261.  
  262.    if (c * ctx->backface_sign > 0)
  263.       return;
  264.  
  265.    facing = (c<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
  266.    tricaps = ctx->IndirectTriangles;
  267.    
  268.    if (tricaps & DD_TRI_OFFSET) {
  269.       /* finish computing plane equation of polygon, compute offset */
  270.       GLfloat fz = win[v2][2] - win[v0][2];
  271.       GLfloat ez = win[v1][2] - win[v0][2];
  272.       GLfloat a = ey*fz-ez*fy;
  273.       GLfloat b = ez*fx-ex*fz;
  274.       offset_polygon( ctx, a, b, c );
  275.    }
  276.  
  277.    if (tricaps & DD_TRI_LIGHT_TWOSIDE) {
  278.       VB->Specular = VB->Spec[facing];
  279.       VB->ColorPtr = VB->Color[facing];
  280.       VB->IndexPtr = VB->Index[facing];
  281.    }
  282.  
  283.    if (tricaps & DD_TRI_UNFILLED) {
  284.       GLuint vlist[3];
  285.       vlist[0] = v0;
  286.       vlist[1] = v1;
  287.       vlist[2] = v2;
  288.       unfilled_polygon( ctx, 3, vlist, pv, facing );
  289.    }
  290.    else {
  291.       (*ctx->Driver.TriangleFunc)( ctx, v0, v1, v2, pv );
  292.    }
  293. }
  294.  
  295.  
  296.  
  297. /* Implements triangle_rendering when (IndirectTriangles & DD_SW_SETUP)
  298.  * is non-zero.
  299.  */
  300. static void render_quad( GLcontext *ctx, GLuint v0, GLuint v1,
  301.                          GLuint v2, GLuint v3, GLuint pv )
  302. {
  303.    struct vertex_buffer *VB = ctx->VB;
  304.    GLfloat (*win)[4] = VB->Win.data;
  305.    GLfloat ex = win[v2][0] - win[v0][0];
  306.    GLfloat ey = win[v2][1] - win[v0][1];
  307.    GLfloat fx = win[v3][0] - win[v1][0];
  308.    GLfloat fy = win[v3][1] - win[v1][1];
  309.    GLfloat c = ex*fy-ey*fx;
  310.    GLuint facing;
  311.    GLuint tricaps;
  312.  
  313.    if (c * ctx->backface_sign > 0)
  314.       return;
  315.  
  316.    facing = (c<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
  317.    tricaps = ctx->IndirectTriangles;
  318.    (void) tricaps;  /* not needed? */
  319.  
  320.    if (ctx->IndirectTriangles & DD_TRI_OFFSET) {
  321.       GLfloat ez = win[v2][2] - win[v0][2];
  322.       GLfloat fz = win[v3][2] - win[v1][2];
  323.       GLfloat a = ey*fz-ez*fy;
  324.       GLfloat b = ez*fx-ex*fz;
  325.       offset_polygon( ctx, a, b, c );
  326.    }
  327.  
  328.  
  329.    if (ctx->IndirectTriangles & DD_TRI_LIGHT_TWOSIDE) {
  330.       VB->Specular = VB->Spec[facing];
  331.       VB->ColorPtr = VB->Color[facing];
  332.       VB->IndexPtr = VB->Index[facing];
  333.    }
  334.  
  335.  
  336.    /* Render the quad! */
  337.    if (ctx->IndirectTriangles & DD_TRI_UNFILLED) {
  338.       GLuint vlist[4];
  339.       vlist[0] = v0;
  340.       vlist[1] = v1;
  341.       vlist[2] = v2;
  342.       vlist[3] = v3;
  343.       unfilled_polygon( ctx, 4, vlist, pv, facing );
  344.    }
  345.    else {
  346.       (*ctx->Driver.QuadFunc)( ctx, v0, v1, v2, v3, pv );
  347.    }
  348. }
  349.  
  350.  
  351.  
  352.  
  353.  
  354. extern const char *gl_prim_name[];
  355.  
  356.  
  357. /*
  358.  * Either the vertex buffer is full (VB->Count==VB_MAX) or glEnd() has been
  359.  * called.  Render the primitives defined by the vertices and reset the
  360.  * buffer.
  361.  *
  362.  * This function won't be called if the device driver implements a
  363.  * RenderVB() function.
  364.  */
  365.  
  366. #define NEED_EDGEFLAG_SETUP (ctx->TriangleCaps & DD_TRI_UNFILLED)
  367.  
  368. #define EDGEFLAG_TRI( i2, i1, i, pv, parity)        \
  369. do {                            \
  370.   eflag[i2] = eflag[i1] = 1; eflag[i] = 2;        \
  371. } while (0)
  372.  
  373. #define EDGEFLAG_QUAD( i3, i2, i1, i, pv)        \
  374. do {                            \
  375.   eflag[i3] = eflag[i2] = eflag[i1] = 1; eflag[i] = 2;    \
  376. } while(0)
  377.  
  378.  
  379. /* Culled and possibly clipped primitives.
  380.  */
  381. #define RENDER_POINTS( start, count )            \
  382.    (void) cullmask;                    \
  383.    (*ctx->Driver.PointsFunc)( ctx, start, count-1 );
  384.  
  385.  
  386. #define RENDER_LINE( i1, i )            \
  387. do {                        \
  388.    const GLubyte flags = cullmask[i];        \
  389.                         \
  390.    if (!(flags & PRIM_NOT_CULLED))        \
  391.       continue;                    \
  392.                         \
  393.    if (flags & PRIM_ANY_CLIP)            \
  394.       gl_render_clipped_line( ctx, i1, i );    \
  395.    else                        \
  396.       ctx->Driver.LineFunc( ctx, i1, i, i );    \
  397. } while (0)
  398.  
  399.  
  400.  
  401. #define RENDER_TRI( i2, i1, i, pv, parity)        \
  402. do {                            \
  403.    const GLubyte flags = cullmask[i];            \
  404.                             \
  405.    if (!(flags & PRIM_NOT_CULLED))            \
  406.       continue;                        \
  407.                             \
  408.    if (flags & PRIM_ANY_CLIP) {                \
  409.       if (parity) {                    \
  410.      vlist[0] = i1;                    \
  411.      vlist[1] = i2;                    \
  412.      vlist[2] = i;                    \
  413.       } else {                        \
  414.      vlist[0] = i2;                    \
  415.      vlist[1] = i1;                    \
  416.      vlist[2] = i;                    \
  417.       }                            \
  418.       gl_render_clipped_triangle( ctx, 3, vlist, pv );    \
  419.    } else if (parity)                     \
  420.       ctx->TriangleFunc( ctx, i1, i2, i, pv );        \
  421.    else                            \
  422.       ctx->TriangleFunc( ctx, i2, i1, i, pv );        \
  423.                             \
  424. } while (0)
  425.  
  426.  
  427. #define RENDER_QUAD( i3, i2, i1, i, pv)            \
  428. do {                            \
  429.    const GLubyte flags = cullmask[i];            \
  430.                             \
  431.    if (!(flags & PRIM_NOT_CULLED))            \
  432.       continue;                        \
  433.                             \
  434.    if (flags&PRIM_ANY_CLIP) {                \
  435.       vlist[0] = i3;                    \
  436.       vlist[1] = i2;                    \
  437.       vlist[2] = i1;                    \
  438.       vlist[3] = i;                    \
  439.       gl_render_clipped_triangle( ctx, 4, vlist, pv );    \
  440.    } else                        \
  441.       ctx->QuadFunc( ctx, i3, i2, i1, i, pv );        \
  442. } while (0)
  443.  
  444.  
  445. #define LOCAL_VARS                \
  446.     GLcontext *ctx = VB->ctx;            \
  447.     const GLubyte *cullmask = VB->CullMask;    \
  448.     GLuint vlist[VB_SIZE];            \
  449.     GLubyte *eflag = VB->EdgeFlagPtr->data;        \
  450.     GLuint *stipplecounter = &VB->ctx->StippleCounter; \
  451.     (void) vlist; (void) eflag; (void) stipplecounter;
  452.  
  453. #define TAG(x) x##_cull
  454. #define INIT(x)  FLUSH_PRIM(x)
  455. #define RESET_STIPPLE *stipplecounter = 0
  456. #include "render_tmp.h"
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464. /* Direct, no clipping or culling.
  465.  */
  466. #define RENDER_POINTS( start, count ) \
  467.    (*ctx->Driver.PointsFunc)( ctx, start, count-1 )
  468.  
  469. #define RENDER_LINE( i1, i ) \
  470.    (*ctx->Driver.LineFunc)( ctx, i1, i, i )
  471.  
  472. #define RENDER_TRI( i2, i1, i, pv, parity )    \
  473. do {                        \
  474.    if (parity)                    \
  475.       ctx->TriangleFunc( ctx, i1, i2, i, pv );    \
  476.    else                        \
  477.       ctx->TriangleFunc( ctx, i2, i1, i, pv );    \
  478. } while (0)
  479.  
  480.  
  481. #define RENDER_QUAD( i3, i2, i1, i, pv )    \
  482.    ctx->QuadFunc( ctx, i3, i2, i1, i, i );
  483.  
  484. #define TAG(x) x##_raw
  485.  
  486. #define LOCAL_VARS                  \
  487.     GLcontext *ctx = VB->ctx;            \
  488.     GLubyte *eflag = VB->EdgeFlagPtr->data;    \
  489.     GLuint *stipplecounter = &VB->ctx->StippleCounter; \
  490.     (void) eflag; (void) stipplecounter;
  491.  
  492. #define INIT(x)  FLUSH_PRIM(x);
  493. #define RESET_STIPPLE *stipplecounter = 0
  494. #include "render_tmp.h"
  495.  
  496.  
  497.  
  498.  
  499. /* Direct, with the possibility of clipping.
  500.  */ 
  501. #define RENDER_POINTS( start, count )            \
  502.    (*ctx->Driver.PointsFunc)( ctx, start, count-1 )
  503.  
  504. #define RENDER_LINE( i1, i )            \
  505.    gl_render_clipped_line2( ctx, i1, i )
  506.  
  507. #define RENDER_TRI( i2, i1, i, pv, parity)    \
  508. do {                        \
  509.   GLuint e2=i2, e1=i1;                \
  510.   if (parity) { GLuint t=e2; e2=e1; e1=t; }    \
  511.   gl_render_clipped_triangle2(ctx,e2,e1,i,pv);    \
  512. } while (0)
  513.  
  514. #define RENDER_QUAD( i3, i2, i1, i, pv)        \
  515. do {                        \
  516.   gl_render_clipped_triangle2(ctx,i3,i2,i1,pv);    \
  517.   gl_render_clipped_triangle2(ctx,i3,i1,i,pv);    \
  518. } while (0)
  519.  
  520. /*    gl_render_clipped_triangle2(ctx,i3,i2,i,pv); */
  521. /*    gl_render_clipped_triangle2(ctx,i2,i1,i,pv); */
  522.  
  523.  
  524. #define LOCAL_VARS                  \
  525.     GLcontext *ctx = VB->ctx;            \
  526.     GLubyte *eflag = VB->EdgeFlagPtr->data;    \
  527.     GLuint *stipplecounter = &VB->ctx->StippleCounter; \
  528.     (void) eflag; (void) stipplecounter;
  529.  
  530. #define INIT(x)  FLUSH_PRIM(x);
  531. #define TAG(x) x##_clipped
  532. #define RESET_STIPPLE *stipplecounter = 0
  533.  
  534. #include "render_tmp.h"
  535.  
  536. /* Bits:
  537.  *    0x1 - draw this edge if it is first or second in a triangle.
  538.  *    0x2 - draw this edge if it is last in a triangle.
  539.  *    0x4 - placeholder for multipass rendering.
  540.  *
  541.  * Bits 0x1 and 0x2 are cleared after they are used.  Bit 0x4 is used
  542.  * to stop these values going to zero in multipass rendering. 
  543.  *
  544.  * Clipping introduces vertices on outgoing edges with edgeflag 0x1.
  545.  * Incoming edges retain the value of the clipped vertex, with the following 
  546.  * masks:
  547.  *    - If the incoming edge originates from the last vertex in the
  548.  *      clipped primitive (triangle or quad), the introduced vertex 
  549.  *      retains both bits (0x3) of the original flag.
  550.  *    - All other introduced vertices retain only bit 1 (0x1).
  551.  *
  552.  * In a horrible hack I've had to push tristrips, fans & quadstrip handling 
  553.  * into render_tmp.h...
  554.  *
  555.  * Keith. 
  556.  */
  557. void gl_setup_edgeflag( struct vertex_buffer *VB, 
  558.             GLenum prim, 
  559.             GLuint start, 
  560.             GLuint count,
  561.             GLuint parity )
  562. {
  563.    GLubyte *flag = VB->EdgeFlagPtr->data + start;
  564.    GLuint n = count - start;
  565.    GLuint i;
  566.    (void) parity;
  567.  
  568.    switch (prim) {
  569.    case GL_TRIANGLES:
  570.       for (i = 0 ; i < n-2 ; i+=3) {
  571.      if (flag[i])   flag[i]   = 0x5;
  572.      if (flag[i+1]) flag[i+1] = 0x5;
  573.      if (flag[i+2]) flag[i+2] = 0x6;
  574.       }
  575.       break;
  576.    case GL_QUADS:
  577.       for (i = 0 ; i < n-3 ; i+=4) {
  578.      if (flag[i])   flag[i]   = 0x5;
  579.      if (flag[i+1]) flag[i+1] = 0x5;
  580.      if (flag[i+2]) flag[i+2] = 0x5;
  581.      if (flag[i+3]) flag[i+3] = 0x6;
  582.       }
  583.       break;
  584.    case GL_POLYGON:
  585.       for (i = 0 ; i < n-1 ; i++) {
  586.      if (flag[i]) flag[i] = 0x5;
  587.       }
  588.       if (flag[i]) flag[i] = 0x6;
  589.       break;
  590.    default:
  591.       break;
  592.    }
  593. }
  594.  
  595.  
  596.  
  597. /* Could eventually generalize to handle changes of rasterization
  598.  * state other than change-of-primitive.  An example might be 
  599.  * some bind-texture calls.
  600.  */
  601. void gl_render_vb( struct vertex_buffer *VB )
  602. {
  603.    GLcontext *ctx = VB->ctx;
  604.    GLuint i, next, prim;
  605.    GLuint parity = VB->Parity;
  606.    render_func *tab;
  607.    GLuint count = VB->Count;
  608.    GLint p = 0;
  609.  
  610.    if (VB->Indirect) { 
  611. /*        gl_render_vb_indirect( VB, VB );   */
  612.       return; 
  613.    } else if (VB->CullMode & CULL_MASK_ACTIVE) {
  614.       tab = ctx->Driver.RenderVBCulledTab;
  615.    } else if (VB->CullMode & CLIP_MASK_ACTIVE) {
  616.       tab = ctx->Driver.RenderVBClippedTab;
  617.    } else {
  618.       tab = ctx->Driver.RenderVBRawTab;
  619.    }
  620.  
  621.    if (!VB->CullDone)
  622.       gl_fast_copy_vb( VB );
  623.  
  624.    if (ctx->TriangleCaps & DD_TRI_UNFILLED)
  625.       gl_import_client_data( VB, VERT_EDGE, VEC_WRITABLE|VEC_GOOD_STRIDE );
  626.  
  627.    gl_import_client_data( VB, ctx->RenderFlags,
  628.               (VB->ClipOrMask 
  629.                ? VEC_WRITABLE|VEC_GOOD_STRIDE
  630.                : VEC_GOOD_STRIDE));
  631.  
  632.    if (/*  ctx->Current.Primitive == GL_POLYGON+1 &&  */
  633.       ctx->Driver.RenderStart)
  634.       ctx->Driver.RenderStart( ctx );
  635.  
  636.  
  637.    do
  638.    {      
  639.       for ( i= VB->CopyStart ; i < count ; parity = 0, i = next ) 
  640.       {
  641.      prim = VB->Primitive[i];
  642.      next = VB->NextPrimitive[i];
  643.  
  644.      if (ctx->TriangleCaps & DD_TRI_UNFILLED) 
  645.         gl_setup_edgeflag(VB, prim, i, next, parity);
  646.  
  647.      tab[prim]( VB, i, next, parity );
  648.  
  649.      if (ctx->TriangleCaps & DD_TRI_LIGHT_TWOSIDE) {
  650.         VB->Specular = VB->Spec[0];
  651.         VB->ColorPtr = VB->Color[0];
  652.         VB->IndexPtr = VB->Index[0];
  653.      }
  654.       }
  655.  
  656.    } while (ctx->Driver.MultipassFunc &&
  657.         ctx->Driver.MultipassFunc( VB, ++p ));
  658.  
  659.    if (ctx->PB->count > 0) 
  660.       gl_flush_pb(ctx);
  661.  
  662.    if (/*  ctx->Current.Primitive == GL_POLYGON+1 &&  */
  663.       ctx->Driver.RenderFinish)
  664.       ctx->Driver.RenderFinish( ctx );
  665. }
  666.  
  667.  
  668. void gl_reduced_prim_change( GLcontext *ctx, GLenum prim )
  669. {
  670.    if (ctx->PB->count > 0) 
  671.       gl_flush_pb(ctx);    
  672.  
  673.    ctx->PB->count = 0;                
  674.    ctx->PB->mono = GL_FALSE;            
  675.    
  676.    if (ctx->PB->primitive != prim) {
  677.       ctx->PB->primitive = prim;            
  678.  
  679.       if (ctx->Driver.ReducedPrimitiveChange)
  680.      ctx->Driver.ReducedPrimitiveChange( ctx, prim );
  681.    }
  682. }
  683.  
  684.  
  685. void gl_set_render_vb_function( GLcontext *ctx )
  686. {
  687.    if (ctx->Driver.RenderVBCulledTab == 0)
  688.       ctx->Driver.RenderVBCulledTab = render_tab_cull;
  689.  
  690.    if (ctx->Driver.RenderVBClippedTab == 0)
  691.       ctx->Driver.RenderVBClippedTab = render_tab_clipped;
  692.  
  693.    if (ctx->Driver.RenderVBRawTab == 0)
  694.       ctx->Driver.RenderVBRawTab = render_tab_raw;
  695.  
  696.    /* Culling will be done earlier by gl_cull_vb().
  697.     */
  698.    if (ctx->IndirectTriangles & (DD_SW_SETUP & ~DD_TRI_CULL)) {
  699.       ctx->TriangleFunc = render_triangle;
  700.       ctx->QuadFunc = render_quad;
  701.    } else {
  702.       ctx->TriangleFunc = ctx->Driver.TriangleFunc;
  703.       ctx->QuadFunc = ctx->Driver.QuadFunc;
  704.    }
  705.  
  706.    if (ctx->IndirectTriangles & (DD_SW_SETUP)) {
  707.       ctx->ClippedTriangleFunc = render_triangle;
  708.    } else {
  709.       ctx->ClippedTriangleFunc = ctx->TriangleFunc;
  710.    }
  711.  
  712. }
  713.  
  714. void gl_init_vbrender( void )
  715. {
  716.    render_init_raw();
  717.    render_init_cull();
  718.    render_init_clipped();
  719. }
  720.  
  721.  
  722.  
  723.  
  724.