xref: /reactos/dll/opengl/mesa/vbrender.c (revision 5417742f)
1 /* $Id: vbrender.c,v 1.21 1998/01/18 15:04:48 brianp Exp $ */
2 
3 /*
4  * Mesa 3-D graphics library
5  * Version:  2.6
6  * Copyright (C) 1995-1997  Brian Paul
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  * $Log: vbrender.c,v $
26  * Revision 1.21  1998/01/18 15:04:48  brianp
27  * fixed clipmask bug in gl_reset_vb() (reported by Michael Callahan)
28  *
29  * Revision 1.20  1998/01/09 02:49:33  brianp
30  * cleaned-up gl_reset_vb(), added small GL_POLYGON optimization
31  *
32  * Revision 1.19  1997/12/29 23:49:57  brianp
33  * added a call to gl_update_lighting() in gl_reset_vb() to fix material bug
34  *
35  * Revision 1.18  1997/12/19 03:36:42  brianp
36  * check bit-wise AND of vertex clip masks to cull polygons sooner
37  *
38  * Revision 1.17  1997/12/09 02:56:57  brianp
39  * in render_clipped_polygon() only recompute window coords for new verts
40  *
41  * Revision 1.16  1997/11/20 00:00:47  brianp
42  * only call Driver.RasterSetup() once in render_clipped_polygon()
43  *
44  * Revision 1.15  1997/09/18 01:32:47  brianp
45  * fixed divide by zero problem for "weird" projection matrices
46  *
47  * Revision 1.14  1997/08/13 01:31:41  brianp
48  * cleaned up code involving LightTwoSide
49  *
50  * Revision 1.13  1997/07/24 01:25:27  brianp
51  * changed precompiled header symbol from PCH to PC_HEADER
52  *
53  * Revision 1.12  1997/07/11 02:19:52  brianp
54  * flat-shaded quads in a strip were miscolored if clipped (Randy Frank)
55  *
56  * Revision 1.11  1997/05/28 03:26:49  brianp
57  * added precompiled header (PCH) support
58  *
59  * Revision 1.10  1997/05/16 02:09:26  brianp
60  * clipped GL_TRIANGLE_STRIP triangles sometimes got wrong provoking vertex
61  *
62  * Revision 1.9  1997/04/30 02:20:00  brianp
63  * fixed a line clipping bug in GL_LINE_LOOPs
64  *
65  * Revision 1.8  1997/04/29 01:31:07  brianp
66  * added RasterSetup() function to device driver
67  *
68  * Revision 1.7  1997/04/24 00:30:17  brianp
69  * optimized glTexCoord2() code
70  *
71  * Revision 1.6  1997/04/20 19:47:06  brianp
72  * fixed an error message, added a comment
73  *
74  * Revision 1.5  1997/04/20 15:59:30  brianp
75  * removed VERTEX2_BIT stuff
76  *
77  * Revision 1.4  1997/04/20 15:27:34  brianp
78  * removed odd_flag from all polygon rendering functions
79  *
80  * Revision 1.3  1997/04/12 12:26:06  brianp
81  * now directly call ctx->Driver.Points/Line/Triangle/QuadFunc
82  *
83  * Revision 1.2  1997/04/07 03:01:11  brianp
84  * optimized vertex[234] code
85  *
86  * Revision 1.1  1997/04/02 03:14:14  brianp
87  * Initial revision
88  *
89  */
90 
91 
92 /*
93  * Render points, lines, and polygons.  The only entry point to this
94  * file is the gl_render_vb() function.  This function is called after
95  * the vertex buffer has filled up or glEnd() has been called.
96  *
97  * This file basically only makes calls to the clipping functions and
98  * the point, line and triangle rasterizers via the function pointers.
99  *    context->Driver.PointsFunc()
100  *    context->Driver.LineFunc()
101  *    context->Driver.TriangleFunc()
102  */
103 
104 
105 #ifdef PC_HEADER
106 #include "all.h"
107 #else
108 #include "clip.h"
109 #include "context.h"
110 #include "light.h"
111 #include "macros.h"
112 #include "matrix.h"
113 #include "pb.h"
114 #include "types.h"
115 #include "vb.h"
116 #include "vbrender.h"
117 #include "xform.h"
118 #endif
119 
120 
121 /*
122  * This file implements rendering of points, lines and polygons defined by
123  * vertices in the vertex buffer.
124  */
125 
126 
127 
128 #ifdef PROFILE
129 #  define START_PROFILE				\
130 	{					\
131 	   GLdouble t0 = gl_time();
132 
133 #  define END_PROFILE( TIMER, COUNTER, INCR )	\
134 	   TIMER += (gl_time() - t0);		\
135 	   COUNTER += INCR;			\
136 	}
137 #else
138 #  define START_PROFILE
139 #  define END_PROFILE( TIMER, COUNTER, INCR )
140 #endif
141 
142 
143 
144 
145 /*
146  * Render a line segment from VB[v1] to VB[v2] when either one or both
147  * endpoints must be clipped.
148  */
149 static void render_clipped_line( GLcontext *ctx, GLuint v1, GLuint v2 )
150 {
151    GLfloat ndc_x, ndc_y, ndc_z;
152    GLuint provoking_vertex;
153    struct vertex_buffer *VB = ctx->VB;
154 
155    /* which vertex dictates the color when flat shading: */
156    provoking_vertex = v2;
157 
158    /*
159     * Clipping may introduce new vertices.  New vertices will be stored
160     * in the vertex buffer arrays starting with location VB->Free.  After
161     * we've rendered the line, these extra vertices can be overwritten.
162     */
163    VB->Free = VB_MAX;
164 
165    /* Clip against user clipping planes */
166    if (ctx->Transform.AnyClip) {
167       GLuint orig_v1 = v1, orig_v2 = v2;
168       if (gl_userclip_line( ctx, &v1, &v2 )==0)
169 	return;
170       /* Apply projection matrix:  clip = Proj * eye */
171       if (v1!=orig_v1) {
172          TRANSFORM_POINT( VB->Clip[v1], ctx->ProjectionMatrix, VB->Eye[v1] );
173       }
174       if (v2!=orig_v2) {
175          TRANSFORM_POINT( VB->Clip[v2], ctx->ProjectionMatrix, VB->Eye[v2] );
176       }
177    }
178 
179    /* Clip against view volume */
180    if (gl_viewclip_line( ctx, &v1, &v2 )==0)
181       return;
182 
183    /* Transform from clip coords to ndc:  ndc = clip / W */
184    if (VB->Clip[v1][3] != 0.0F) {
185       GLfloat wInv = 1.0F / VB->Clip[v1][3];
186       ndc_x = VB->Clip[v1][0] * wInv;
187       ndc_y = VB->Clip[v1][1] * wInv;
188       ndc_z = VB->Clip[v1][2] * wInv;
189    }
190    else {
191       /* Can't divide by zero, so... */
192       ndc_x = ndc_y = ndc_z = 0.0F;
193    }
194 
195    /* Map ndc coord to window coords. */
196    VB->Win[v1][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
197    VB->Win[v1][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
198    VB->Win[v1][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
199 
200    /* Transform from clip coords to ndc:  ndc = clip / W */
201    if (VB->Clip[v2][3] != 0.0F) {
202       GLfloat wInv = 1.0F / VB->Clip[v2][3];
203       ndc_x = VB->Clip[v2][0] * wInv;
204       ndc_y = VB->Clip[v2][1] * wInv;
205       ndc_z = VB->Clip[v2][2] * wInv;
206    }
207    else {
208       /* Can't divide by zero, so... */
209       ndc_x = ndc_y = ndc_z = 0.0F;
210    }
211 
212    /* Map ndc coord to window coords. */
213    VB->Win[v2][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
214    VB->Win[v2][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
215    VB->Win[v2][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
216 
217    if (ctx->Driver.RasterSetup) {
218       /* Device driver rasterization setup */
219       (*ctx->Driver.RasterSetup)( ctx, v1, v1+1 );
220       (*ctx->Driver.RasterSetup)( ctx, v2, v2+1 );
221    }
222 
223    START_PROFILE
224    (*ctx->Driver.LineFunc)( ctx, v1, v2, provoking_vertex );
225    END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
226 }
227 
228 
229 
230 /*
231  * Compute Z offsets for a polygon with plane defined by (A,B,C,D)
232  * D is not needed.
233  */
234 static void offset_polygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c )
235 {
236    GLfloat ac, bc, m;
237    GLfloat offset;
238 
239    if (c<0.001F && c>-0.001F) {
240       /* to prevent underflow problems */
241       offset = 0.0F;
242    }
243    else {
244       ac = a / c;
245       bc = b / c;
246       if (ac<0.0F)  ac = -ac;
247       if (bc<0.0F)  bc = -bc;
248       m = MAX2( ac, bc );
249       /* m = sqrt( ac*ac + bc*bc ); */
250 
251       offset = m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits;
252    }
253 
254    ctx->PointZoffset   = ctx->Polygon.OffsetPoint ? offset : 0.0F;
255    ctx->LineZoffset    = ctx->Polygon.OffsetLine  ? offset : 0.0F;
256    ctx->PolygonZoffset = ctx->Polygon.OffsetFill  ? offset : 0.0F;
257 }
258 
259 
260 
261 /*
262  * When glPolygonMode() is used to specify that the front/back rendering
263  * mode for polygons is not GL_FILL we end up calling this function.
264  */
265 static void unfilled_polygon( GLcontext *ctx,
266                               GLuint n, GLuint vlist[],
267                               GLuint pv, GLuint facing )
268 {
269    GLenum mode = facing ? ctx->Polygon.BackMode : ctx->Polygon.FrontMode;
270    struct vertex_buffer *VB = ctx->VB;
271 
272    if (mode==GL_POINT) {
273       GLint i, j;
274       GLboolean edge;
275 
276       if (   ctx->Primitive==GL_TRIANGLES
277           || ctx->Primitive==GL_QUADS
278           || ctx->Primitive==GL_POLYGON) {
279          edge = GL_FALSE;
280       }
281       else {
282          edge = GL_TRUE;
283       }
284 
285       for (i=0;i<n;i++) {
286          j = vlist[i];
287          if (edge || VB->Edgeflag[j]) {
288             (*ctx->Driver.PointsFunc)( ctx, j, j );
289          }
290       }
291    }
292    else if (mode==GL_LINE) {
293       GLuint i, j0, j1;
294       GLboolean edge;
295 
296       ctx->StippleCounter = 0;
297 
298       if (   ctx->Primitive==GL_TRIANGLES
299           || ctx->Primitive==GL_QUADS
300           || ctx->Primitive==GL_POLYGON) {
301          edge = GL_FALSE;
302       }
303       else {
304          edge = GL_TRUE;
305       }
306 
307       /* draw the edges */
308       for (i=0;i<n;i++) {
309          j0 = (i==0) ? vlist[n-1] : vlist[i-1];
310          j1 = vlist[i];
311          if (edge || VB->Edgeflag[j0]) {
312             START_PROFILE
313             (*ctx->Driver.LineFunc)( ctx, j0, j1, pv );
314             END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
315          }
316       }
317    }
318    else {
319       /* Fill the polygon */
320       GLuint j0, i;
321       j0 = vlist[0];
322       for (i=2;i<n;i++) {
323          START_PROFILE
324          (*ctx->Driver.TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv );
325          END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
326       }
327    }
328 }
329 
330 
331 /*
332  * Compute signed area of the n-sided polgyon specified by vertices vb->Win[]
333  * and vertex list vlist[].
334  * A clockwise polygon will return a negative area.
335  * A counter-clockwise polygon will return a positive area.
336  */
337 static GLfloat polygon_area( const struct vertex_buffer *vb,
338                              GLuint n, const GLuint vlist[] )
339 {
340    GLfloat area = 0.0F;
341    GLint i;
342    for (i=0;i<n;i++) {
343       /* area = sum of trapezoids */
344       GLuint j0 = vlist[i];
345       GLuint j1 = vlist[(i+1)%n];
346       GLfloat x0 = vb->Win[j0][0];
347       GLfloat y0 = vb->Win[j0][1];
348       GLfloat x1 = vb->Win[j1][0];
349       GLfloat y1 = vb->Win[j1][1];
350       GLfloat trapArea = (x0-x1)*(y0+y1);  /* Note: no divide by two here! */
351       area += trapArea;
352    }
353    return area * 0.5F;     /* divide by two now! */
354 }
355 
356 
357 /*
358  * Render a polygon in which doesn't have to be clipped.
359  * Input:  n - number of vertices
360  *         vlist - list of vertices in the polygon.
361  */
362 static void render_polygon( GLcontext *ctx, GLuint n, GLuint vlist[] )
363 {
364    struct vertex_buffer *VB = ctx->VB;
365    GLuint pv;
366 
367    /* which vertex dictates the color when flat shading: */
368    pv = (ctx->Primitive==GL_POLYGON) ? vlist[0] : vlist[n-1];
369 
370    /* Compute orientation of polygon, do cull test, offset, etc */
371    {
372       GLuint facing;   /* 0=front, 1=back */
373       GLfloat area = polygon_area( VB, n, vlist );
374 
375       if (area==0.0F) {
376          /* polygon has zero area, don't draw it */
377          return;
378       }
379 
380       facing = (area<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
381 
382       if ((facing+1) & ctx->Polygon.CullBits) {
383          return;   /* culled */
384       }
385 
386       if (ctx->Polygon.OffsetAny) {
387          /* compute plane equation of polygon, apply offset */
388          GLuint j0 = vlist[0];
389          GLuint j1 = vlist[1];
390          GLuint j2 = vlist[2];
391          GLuint j3 = vlist[ (n==3) ? 0 : 3 ];
392          GLfloat ex = VB->Win[j1][0] - VB->Win[j3][0];
393          GLfloat ey = VB->Win[j1][1] - VB->Win[j3][1];
394          GLfloat ez = VB->Win[j1][2] - VB->Win[j3][2];
395          GLfloat fx = VB->Win[j2][0] - VB->Win[j0][0];
396          GLfloat fy = VB->Win[j2][1] - VB->Win[j0][1];
397          GLfloat fz = VB->Win[j2][2] - VB->Win[j0][2];
398          GLfloat a = ey*fz-ez*fy;
399          GLfloat b = ez*fx-ex*fz;
400          GLfloat c = ex*fy-ey*fx;
401          offset_polygon( ctx, a, b, c );
402       }
403 
404       if (ctx->LightTwoSide) {
405          if (facing==1) {
406             /* use back color or index */
407             VB->Color = VB->Bcolor;
408             VB->Index = VB->Bindex;
409          }
410          else {
411             /* use front color or index */
412             VB->Color = VB->Fcolor;
413             VB->Index = VB->Findex;
414          }
415       }
416 
417       /* Render the polygon! */
418       if (ctx->Polygon.Unfilled) {
419          unfilled_polygon( ctx, n, vlist, pv, facing );
420       }
421       else {
422          /* Draw filled polygon as a triangle fan */
423          GLint i;
424          GLuint j0 = vlist[0];
425          for (i=2;i<n;i++) {
426             START_PROFILE
427             (*ctx->Driver.TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv );
428             END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
429          }
430       }
431    }
432 }
433 
434 
435 
436 /*
437  * Render a polygon in which at least one vertex has to be clipped.
438  * Input:  n - number of vertices
439  *         vlist - list of vertices in the polygon.
440  *                 CCW order = front facing.
441  */
442 static void render_clipped_polygon( GLcontext *ctx, GLuint n, GLuint vlist[] )
443 {
444    GLuint pv;
445    struct vertex_buffer *VB = ctx->VB;
446    GLfloat (*win)[3] = VB->Win;
447 
448    /* which vertex dictates the color when flat shading: */
449    pv = (ctx->Primitive==GL_POLYGON) ? vlist[0] : vlist[n-1];
450 
451    /*
452     * Clipping may introduce new vertices.  New vertices will be stored
453     * in the vertex buffer arrays starting with location VB->Free.  After
454     * we've rendered the polygon, these extra vertices can be overwritten.
455     */
456    VB->Free = VB_MAX;
457 
458    /* Clip against user clipping planes in eye coord space. */
459    if (ctx->Transform.AnyClip) {
460       GLfloat *proj = ctx->ProjectionMatrix;
461       GLuint i;
462       n = gl_userclip_polygon( ctx, n, vlist );
463       if (n<3)
464          return;
465       /* Transform vertices from eye to clip coordinates:  clip = Proj * eye */
466       for (i=0;i<n;i++) {
467          GLuint j = vlist[i];
468          TRANSFORM_POINT( VB->Clip[j], proj, VB->Eye[j] );
469       }
470    }
471 
472    /* Clip against view volume in clip coord space */
473    n = gl_viewclip_polygon( ctx, n, vlist );
474    if (n<3)
475       return;
476 
477    /* Transform new vertices from clip to ndc to window coords.    */
478    /* ndc = clip / W    window = viewport_mapping(ndc)             */
479    /* Note that window Z values are scaled to the range of integer */
480    /* depth buffer values.                                         */
481    {
482       GLfloat sx = ctx->Viewport.Sx;
483       GLfloat tx = ctx->Viewport.Tx;
484       GLfloat sy = ctx->Viewport.Sy;
485       GLfloat ty = ctx->Viewport.Ty;
486       GLfloat sz = ctx->Viewport.Sz;
487       GLfloat tz = ctx->Viewport.Tz;
488       GLuint i;
489       /* Only need to compute window coords for new vertices */
490       for (i=VB_MAX; i<VB->Free; i++) {
491          if (VB->Clip[i][3] != 0.0F) {
492             GLfloat wInv = 1.0F / VB->Clip[i][3];
493             win[i][0] = VB->Clip[i][0] * wInv * sx + tx;
494             win[i][1] = VB->Clip[i][1] * wInv * sy + ty;
495             win[i][2] = VB->Clip[i][2] * wInv * sz + tz;
496          }
497          else {
498             /* Can't divide by zero, so... */
499             win[i][0] = win[i][1] = win[i][2] = 0.0F;
500          }
501       }
502       if (ctx->Driver.RasterSetup && (VB->Free > VB_MAX)) {
503          /* Device driver raster setup for newly introduced vertices */
504          (*ctx->Driver.RasterSetup)(ctx, VB_MAX, VB->Free);
505       }
506 
507 #ifdef DEBUG
508       {
509          int i, j;
510          for (i=0;i<n;i++) {
511             j = vlist[i];
512             if (VB->ClipMask[j]) {
513                /* Uh oh!  There should be no clip bits set in final polygon! */
514                int k, l;
515                printf("CLIPMASK %d %d %02x\n", i, j, VB->ClipMask[j]);
516                printf("%f %f %f %f\n", VB->Eye[j][0], VB->Eye[j][1],
517                       VB->Eye[j][2], VB->Eye[j][3]);
518                printf("%f %f %f %f\n", VB->Clip[j][0], VB->Clip[j][1],
519                       VB->Clip[j][2], VB->Clip[j][3]);
520                for (k=0;k<n;k++) {
521                   l = vlist[k];
522                   printf("%d %d %02x\n", k, l, VB->ClipMask[l]);
523                }
524             }
525          }
526       }
527 #endif
528    }
529 
530    /* Compute orientation of polygon, do cull test, offset, etc */
531    {
532       GLuint facing;   /* 0=front, 1=back */
533       GLfloat area = polygon_area( VB, n, vlist );
534 
535       if (area==0.0F) {
536          /* polygon has zero area, don't draw it */
537          return;
538       }
539 
540       facing = (area<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
541 
542       if ((facing+1) & ctx->Polygon.CullBits) {
543          return;   /* culled */
544       }
545 
546       if (ctx->Polygon.OffsetAny) {
547          /* compute plane equation of polygon, apply offset */
548          GLuint j0 = vlist[0];
549          GLuint j1 = vlist[1];
550          GLuint j2 = vlist[2];
551          GLuint j3 = vlist[ (n==3) ? 0 : 3 ];
552          GLfloat ex = win[j1][0] - win[j3][0];
553          GLfloat ey = win[j1][1] - win[j3][1];
554          GLfloat ez = win[j1][2] - win[j3][2];
555          GLfloat fx = win[j2][0] - win[j0][0];
556          GLfloat fy = win[j2][1] - win[j0][1];
557          GLfloat fz = win[j2][2] - win[j0][2];
558          GLfloat a = ey*fz-ez*fy;
559          GLfloat b = ez*fx-ex*fz;
560          GLfloat c = ex*fy-ey*fx;
561          offset_polygon( ctx, a, b, c );
562       }
563 
564       if (ctx->LightTwoSide) {
565          if (facing==1) {
566             /* use back color or index */
567             VB->Color = VB->Bcolor;
568             VB->Index = VB->Bindex;
569          }
570          else {
571             /* use front color or index */
572             VB->Color = VB->Fcolor;
573             VB->Index = VB->Findex;
574          }
575       }
576 
577       /* Render the polygon! */
578       if (ctx->Polygon.Unfilled) {
579          unfilled_polygon( ctx, n, vlist, pv, facing );
580       }
581       else {
582          /* Draw filled polygon as a triangle fan */
583          GLint i;
584          GLuint j0 = vlist[0];
585          for (i=2;i<n;i++) {
586             START_PROFILE
587             (*ctx->Driver.TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv );
588             END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
589          }
590       }
591    }
592 }
593 
594 
595 
596 /*
597  * Render an un-clipped triangle.
598  * v0, v1, v2 - vertex indexes.  CCW order = front facing
599  * pv - provoking vertex
600  */
601 static void render_triangle( GLcontext *ctx,
602                              GLuint v0, GLuint v1, GLuint v2, GLuint pv )
603 {
604    struct vertex_buffer *VB = ctx->VB;
605    GLfloat ex, ey, fx, fy, c;
606    GLuint facing;  /* 0=front, 1=back */
607    GLfloat (*win)[3] = VB->Win;
608 
609    /* Compute orientation of triangle */
610    ex = win[v1][0] - win[v0][0];
611    ey = win[v1][1] - win[v0][1];
612    fx = win[v2][0] - win[v0][0];
613    fy = win[v2][1] - win[v0][1];
614    c = ex*fy-ey*fx;
615 
616    if (c==0.0F) {
617       /* polygon is perpindicular to view plane, don't draw it */
618       return;
619    }
620 
621    facing = (c<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
622 
623    if ((facing+1) & ctx->Polygon.CullBits) {
624       return;   /* culled */
625    }
626 
627    if (ctx->Polygon.OffsetAny) {
628       /* finish computing plane equation of polygon, compute offset */
629       GLfloat fz = win[v2][2] - win[v0][2];
630       GLfloat ez = win[v1][2] - win[v0][2];
631       GLfloat a = ey*fz-ez*fy;
632       GLfloat b = ez*fx-ex*fz;
633       offset_polygon( ctx, a, b, c );
634    }
635 
636    if (ctx->LightTwoSide) {
637       if (facing==1) {
638          /* use back color or index */
639          VB->Color = VB->Bcolor;
640          VB->Index = VB->Bindex;
641       }
642       else {
643          /* use front color or index */
644          VB->Color = VB->Fcolor;
645          VB->Index = VB->Findex;
646       }
647    }
648 
649    if (ctx->Polygon.Unfilled) {
650       GLuint vlist[3];
651       vlist[0] = v0;
652       vlist[1] = v1;
653       vlist[2] = v2;
654       unfilled_polygon( ctx, 3, vlist, pv, facing );
655    }
656    else {
657       START_PROFILE
658       (*ctx->Driver.TriangleFunc)( ctx, v0, v1, v2, pv );
659       END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
660    }
661 }
662 
663 
664 
665 /*
666  * Render an un-clipped quadrilateral.
667  * v0, v1, v2, v3 : CCW order = front facing
668  * pv - provoking vertex
669  */
670 static void render_quad( GLcontext *ctx, GLuint v0, GLuint v1,
671                          GLuint v2, GLuint v3, GLuint pv )
672 {
673    struct vertex_buffer *VB = ctx->VB;
674    GLfloat ex, ey, fx, fy, c;
675    GLuint facing;  /* 0=front, 1=back */
676    GLfloat (*win)[3] = VB->Win;
677 
678    /* Compute polygon orientation */
679    ex = win[v2][0] - win[v0][0];
680    ey = win[v2][1] - win[v0][1];
681    fx = win[v3][0] - win[v1][0];
682    fy = win[v3][1] - win[v1][1];
683    c = ex*fy-ey*fx;
684 
685    if (c==0.0F) {
686       /* polygon is perpindicular to view plane, don't draw it */
687       return;
688    }
689 
690    facing = (c<0.0F) ^ (ctx->Polygon.FrontFace==GL_CW);
691 
692    if ((facing+1) & ctx->Polygon.CullBits) {
693       return;   /* culled */
694    }
695 
696    if (ctx->Polygon.OffsetAny) {
697       /* finish computing plane equation of polygon, compute offset */
698       GLfloat ez = win[v2][2] - win[v0][2];
699       GLfloat fz = win[v3][2] - win[v1][2];
700       GLfloat a = ey*fz-ez*fy;
701       GLfloat b = ez*fx-ex*fz;
702       offset_polygon( ctx, a, b, c );
703    }
704 
705    if (ctx->LightTwoSide) {
706       if (facing==1) {
707          /* use back color or index */
708          VB->Color = VB->Bcolor;
709          VB->Index = VB->Bindex;
710       }
711       else {
712          /* use front color or index */
713          VB->Color = VB->Fcolor;
714          VB->Index = VB->Findex;
715       }
716    }
717 
718    /* Render the quad! */
719    if (ctx->Polygon.Unfilled) {
720       GLuint vlist[4];
721       vlist[0] = v0;
722       vlist[1] = v1;
723       vlist[2] = v2;
724       vlist[3] = v3;
725       unfilled_polygon( ctx, 4, vlist, pv, facing );
726    }
727    else {
728       START_PROFILE
729       (*ctx->Driver.QuadFunc)( ctx, v0, v1, v2, v3, pv );
730       END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 )
731    }
732 }
733 
734 
735 
736 /*
737  * When the vertex buffer is full, we transform/render it.  Sometimes we
738  * have to copy the last vertex (or two) to the front of the vertex list
739  * to "continue" the primitive.  For example:  line or triangle strips.
740  * This function is a helper for that.
741  */
742 static void copy_vertex( struct vertex_buffer *vb, GLuint dst, GLuint src )
743 {
744    COPY_4V( vb->Clip[dst], vb->Clip[src] );
745    COPY_4V( vb->Eye[dst], vb->Eye[src] );
746    COPY_3V( vb->Win[dst], vb->Win[src] );
747    COPY_4V( vb->Fcolor[dst], vb->Fcolor[src] );
748    COPY_4V( vb->Bcolor[dst], vb->Bcolor[src] );
749    COPY_4V( vb->TexCoord[dst], vb->TexCoord[src] );
750    vb->Findex[dst] = vb->Findex[src];
751    vb->Bindex[dst] = vb->Bindex[src];
752    vb->Edgeflag[dst] = vb->Edgeflag[src];
753    vb->ClipMask[dst] = vb->ClipMask[src];
754    vb->MaterialMask[dst] = vb->MaterialMask[src];
755    vb->Material[dst][0] = vb->Material[src][0];
756    vb->Material[dst][1] = vb->Material[src][1];
757 }
758 
759 
760 
761 
762 /*
763  * Either the vertex buffer is full (VB->Count==VB_MAX) or glEnd() has been
764  * called.  Render the primitives defined by the vertices and reset the
765  * buffer.
766  *
767  * This function won't be called if the device driver implements a
768  * RenderVB() function.  If the device driver renders the vertex buffer
769  * then the driver must also call gl_reset_vb()!
770  *
771  * Input:  allDone - GL_TRUE = caller is glEnd()
772  *                   GL_FALSE = calling because buffer is full.
773  */
774 void gl_render_vb( GLcontext *ctx, GLboolean allDone )
775 {
776    struct vertex_buffer *VB = ctx->VB;
777    GLuint vlist[VB_SIZE];
778 
779    switch (ctx->Primitive) {
780       case GL_POINTS:
781          START_PROFILE
782          (*ctx->Driver.PointsFunc)( ctx, 0, VB->Count-1 );
783          END_PROFILE( ctx->PointTime, ctx->PointCount, VB->Count )
784 	 break;
785 
786       case GL_LINES:
787          if (VB->ClipOrMask) {
788             GLuint i;
789             for (i=1;i<VB->Count;i+=2) {
790                if (VB->ClipMask[i-1] | VB->ClipMask[i]) {
791                   render_clipped_line( ctx, i-1, i );
792                }
793                else {
794                   START_PROFILE
795                   (*ctx->Driver.LineFunc)( ctx, i-1, i, i );
796                   END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
797                }
798                ctx->StippleCounter = 0;
799             }
800          }
801          else {
802             GLuint i;
803             for (i=1;i<VB->Count;i+=2) {
804                START_PROFILE
805                (*ctx->Driver.LineFunc)( ctx, i-1, i, i );
806                END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
807                ctx->StippleCounter = 0;
808             }
809          }
810 	 break;
811 
812       case GL_LINE_STRIP:
813          if (VB->ClipOrMask) {
814             GLuint i;
815 	    for (i=1;i<VB->Count;i++) {
816                if (VB->ClipMask[i-1] | VB->ClipMask[i]) {
817                   render_clipped_line( ctx, i-1, i );
818                }
819                else {
820                   START_PROFILE
821                   (*ctx->Driver.LineFunc)( ctx, i-1, i, i );
822                   END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
823                }
824 	    }
825          }
826          else {
827             /* no clipping needed */
828             GLuint i;
829 	    for (i=1;i<VB->Count;i++) {
830                START_PROFILE
831                (*ctx->Driver.LineFunc)( ctx, i-1, i, i );
832                END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
833             }
834          }
835          break;
836 
837       case GL_LINE_LOOP:
838          {
839             GLuint i;
840             if (VB->Start==0) {
841                i = 1;  /* start at 0th vertex */
842             }
843             else {
844                i = 2;  /* skip first vertex, we're saving it until glEnd */
845             }
846             while (i<VB->Count) {
847                if (VB->ClipMask[i-1] | VB->ClipMask[i]) {
848                   render_clipped_line( ctx, i-1, i );
849                }
850                else {
851                   START_PROFILE
852                   (*ctx->Driver.LineFunc)( ctx, i-1, i, i );
853                   END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
854                }
855                i++;
856             }
857          }
858          break;
859 
860       case GL_TRIANGLES:
861          if (VB->ClipOrMask) {
862             GLuint i;
863             for (i=2;i<VB->Count;i+=3) {
864                if (VB->ClipMask[i-2] & VB->ClipMask[i-1]
865                    & VB->ClipMask[i] & CLIP_ALL_BITS) {
866                   /* all points clipped by common plane */
867                   continue;
868                }
869                else if (VB->ClipMask[i-2] | VB->ClipMask[i-1] | VB->ClipMask[i]) {
870                   vlist[0] = i-2;
871                   vlist[1] = i-1;
872                   vlist[2] = i-0;
873                   render_clipped_polygon( ctx, 3, vlist );
874                }
875                else {
876                   if (ctx->DirectTriangles) {
877                      START_PROFILE
878                      (*ctx->Driver.TriangleFunc)( ctx, i-2, i-1, i, i );
879                      END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
880                   }
881                   else {
882                      render_triangle( ctx, i-2, i-1, i, i );
883                   }
884                }
885             }
886          }
887          else {
888             /* no clipping needed */
889             GLuint i;
890             if (ctx->DirectTriangles) {
891                for (i=2;i<VB->Count;i+=3) {
892                   START_PROFILE
893                   (*ctx->Driver.TriangleFunc)( ctx, i-2, i-1, i, i );
894                   END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
895                }
896             }
897             else {
898                for (i=2;i<VB->Count;i+=3) {
899                   render_triangle( ctx, i-2, i-1, i, i );
900                }
901             }
902          }
903 	 break;
904 
905       case GL_TRIANGLE_STRIP:
906          if (VB->ClipOrMask) {
907             GLuint i;
908             for (i=2;i<VB->Count;i++) {
909                if (VB->ClipMask[i-2] & VB->ClipMask[i-1]
910                    & VB->ClipMask[i] & CLIP_ALL_BITS) {
911                   /* all points clipped by common plane */
912                   continue;
913                }
914                else if (VB->ClipMask[i-2] | VB->ClipMask[i-1] | VB->ClipMask[i]) {
915                   if (i&1) {
916                      /* reverse vertex order */
917                      vlist[0] = i-1;
918                      vlist[1] = i-2;
919                      vlist[2] = i-0;
920                      render_clipped_polygon( ctx, 3, vlist );
921                   }
922                   else {
923                      vlist[0] = i-2;
924                      vlist[1] = i-1;
925                      vlist[2] = i-0;
926                      render_clipped_polygon( ctx, 3, vlist );
927                   }
928                }
929                else {
930                   if (ctx->DirectTriangles) {
931                      START_PROFILE
932                      (*ctx->Driver.TriangleFunc)( ctx, i-2, i-1, i, i );
933                      END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
934                   }
935                   else {
936                      if (i&1)
937                         render_triangle( ctx, i, i-1, i-2, i );
938                      else
939                         render_triangle( ctx, i-2, i-1, i, i );
940                   }
941                }
942             }
943          }
944          else {
945             /* no vertices were clipped */
946             GLuint i;
947             if (ctx->DirectTriangles) {
948                for (i=2;i<VB->Count;i++) {
949                   START_PROFILE
950                   (*ctx->Driver.TriangleFunc)( ctx, i-2, i-1, i, i );
951                   END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
952                }
953             }
954             else {
955                for (i=2;i<VB->Count;i++) {
956                   if (i&1)
957                      render_triangle( ctx, i, i-1, i-2, i );
958                   else
959                      render_triangle( ctx, i-2, i-1, i, i );
960                }
961             }
962          }
963 	 break;
964 
965       case GL_TRIANGLE_FAN:
966          if (VB->ClipOrMask) {
967             GLuint i;
968             for (i=2;i<VB->Count;i++) {
969                if (VB->ClipMask[0] & VB->ClipMask[i-1] & VB->ClipMask[i]
970                    & CLIP_ALL_BITS) {
971                   /* all points clipped by common plane */
972                   continue;
973                }
974                else if (VB->ClipMask[0] | VB->ClipMask[i-1] | VB->ClipMask[i]) {
975                   vlist[0] = 0;
976                   vlist[1] = i-1;
977                   vlist[2] = i;
978                   render_clipped_polygon( ctx, 3, vlist );
979                }
980                else {
981                   if (ctx->DirectTriangles) {
982                      START_PROFILE
983                      (*ctx->Driver.TriangleFunc)( ctx, 0, i-1, i, i );
984                      END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
985                   }
986                   else {
987                      render_triangle( ctx, 0, i-1, i, i );
988                   }
989                }
990             }
991          }
992          else {
993             /* no clipping needed */
994             GLuint i;
995             if (ctx->DirectTriangles) {
996                for (i=2;i<VB->Count;i++) {
997                   START_PROFILE
998                   (*ctx->Driver.TriangleFunc)( ctx, 0, i-1, i, i );
999                   END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
1000                }
1001             }
1002             else {
1003                for (i=2;i<VB->Count;i++) {
1004                   render_triangle( ctx, 0, i-1, i, i );
1005                }
1006             }
1007          }
1008 	 break;
1009 
1010       case GL_QUADS:
1011          if (VB->ClipOrMask) {
1012             GLuint i;
1013             for (i=3;i<VB->Count;i+=4) {
1014                if (VB->ClipMask[i-3] & VB->ClipMask[i-2]
1015                    & VB->ClipMask[i-1] & VB->ClipMask[i] & CLIP_ALL_BITS) {
1016                   /* all points clipped by common plane */
1017                   continue;
1018                }
1019                else if (VB->ClipMask[i-3] | VB->ClipMask[i-2]
1020                         | VB->ClipMask[i-1] | VB->ClipMask[i]) {
1021                   vlist[0] = i-3;
1022                   vlist[1] = i-2;
1023                   vlist[2] = i-1;
1024                   vlist[3] = i-0;
1025                   render_clipped_polygon( ctx, 4, vlist );
1026                }
1027                else {
1028                   if (ctx->DirectTriangles) {
1029                      START_PROFILE
1030                      (*ctx->Driver.QuadFunc)( ctx, i-3, i-2, i-1, i, i );
1031                      END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 )
1032                   }
1033                   else {
1034                      render_quad( ctx, i-3, i-2, i-1, i, i );
1035                   }
1036                }
1037             }
1038          }
1039          else {
1040             /* no vertices were clipped */
1041             GLuint i;
1042             if (ctx->DirectTriangles) {
1043                for (i=3;i<VB->Count;i+=4) {
1044                   START_PROFILE
1045                   (*ctx->Driver.QuadFunc)( ctx, i-3, i-2, i-1, i, i );
1046                   END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 )
1047                }
1048             }
1049             else {
1050                for (i=3;i<VB->Count;i+=4) {
1051                   render_quad( ctx, i-3, i-2, i-1, i, i );
1052                }
1053             }
1054          }
1055 	 break;
1056 
1057       case GL_QUAD_STRIP:
1058          if (VB->ClipOrMask) {
1059             GLuint i;
1060             for (i=3;i<VB->Count;i+=2) {
1061                if (VB->ClipMask[i-2] & VB->ClipMask[i-3]
1062                    & VB->ClipMask[i-1] & VB->ClipMask[i] & CLIP_ALL_BITS) {
1063                   /* all points clipped by common plane */
1064                   continue;
1065                }
1066                else if (VB->ClipMask[i-2] | VB->ClipMask[i-3]
1067                         | VB->ClipMask[i-1] | VB->ClipMask[i]) {
1068                   vlist[0] = i-1;
1069                   vlist[1] = i-3;
1070                   vlist[2] = i-2;
1071                   vlist[3] = i-0;
1072                   render_clipped_polygon( ctx, 4, vlist );
1073                }
1074                else {
1075                   if (ctx->DirectTriangles) {
1076                      START_PROFILE
1077                      (*ctx->Driver.QuadFunc)( ctx, i-3, i-2, i, i-1, i );
1078                      END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 )
1079                   }
1080                   else {
1081                      render_quad( ctx, i-3, i-2, i, i-1, i );
1082                   }
1083                }
1084             }
1085          }
1086          else {
1087             /* no clipping needed */
1088             GLuint i;
1089             if (ctx->DirectTriangles) {
1090                for (i=3;i<VB->Count;i+=2) {
1091                   START_PROFILE
1092                   (*ctx->Driver.QuadFunc)( ctx, i-3, i-2, i, i-1, i );
1093                   END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 )
1094                }
1095             }
1096             else {
1097                for (i=3;i<VB->Count;i+=2) {
1098                   render_quad( ctx, i-3, i-2, i, i-1, i );
1099                }
1100             }
1101          }
1102 	 break;
1103 
1104       case GL_POLYGON:
1105          if (VB->Count>2) {
1106             if (VB->ClipAndMask & CLIP_ALL_BITS) {
1107                /* all points clipped by common plane, draw nothing */
1108                break;
1109             }
1110             if (VB->ClipOrMask) {
1111                /* need clipping */
1112                GLuint i;
1113                for (i=0;i<VB->Count;i++) {
1114                   vlist[i] = i;
1115                }
1116                render_clipped_polygon( ctx, VB->Count, vlist );
1117             }
1118             else {
1119                /* no clipping needed */
1120                static GLuint const_vlist[VB_SIZE];
1121                static GLboolean initFlag = GL_TRUE;
1122                if (initFlag) {
1123                   /* vertex list always the same, never changes */
1124                   GLuint i;
1125                   for (i=0;i<VB_SIZE;i++) {
1126                      const_vlist[i] = i;
1127                   }
1128                   initFlag = GL_FALSE;
1129                }
1130                render_polygon( ctx, VB->Count, const_vlist );
1131             }
1132          }
1133 	 break;
1134 
1135       default:
1136          /* should never get here */
1137          gl_problem( ctx, "invalid mode in gl_render_vb" );
1138    }
1139 
1140    gl_reset_vb( ctx, allDone );
1141 }
1142 
1143 
1144 #define CLIP_ALL_BITS    0x3f
1145 
1146 
1147 /*
1148  * After we've rendered the primitives in the vertex buffer we call
1149  * this function to reset the vertex buffer.  That is, we prepare it
1150  * for the next batch of vertices.
1151  * Input:  ctx - the context
1152  *         allDone - GL_TRUE = glEnd() was called
1153  *                   GL_FALSE = buffer was filled, more vertices to come
1154  */
1155 void gl_reset_vb( GLcontext *ctx, GLboolean allDone )
1156 {
1157    struct vertex_buffer *VB = ctx->VB;
1158 
1159    /* save a few VB values for the end of this function */
1160    int oldCount = VB->Count;
1161    GLubyte clipOrMask = VB->ClipOrMask;
1162    GLboolean monoMaterial = VB->MonoMaterial;
1163    GLuint vertexSizeMask = VB->VertexSizeMask;
1164 
1165    /* Special case for GL_LINE_LOOP */
1166    if (ctx->Primitive==GL_LINE_LOOP && allDone) {
1167       if (VB->ClipMask[VB->Count-1] | VB->ClipMask[0]) {
1168          render_clipped_line( ctx, VB->Count-1, 0 );
1169       }
1170       else {
1171          START_PROFILE
1172          (*ctx->Driver.LineFunc)( ctx, VB->Count-1, 0, 0 );
1173          END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
1174       }
1175    }
1176 
1177    if (allDone) {
1178       /* glEnd() was called so reset Vertex Buffer to default, empty state */
1179       VB->Start = VB->Count = 0;
1180       VB->ClipOrMask = 0;
1181       VB->ClipAndMask = CLIP_ALL_BITS;
1182       VB->MonoMaterial = GL_TRUE;
1183       VB->MonoNormal = GL_TRUE;
1184       VB->MonoColor = GL_TRUE;
1185       VB->VertexSizeMask = VERTEX3_BIT;
1186       if (VB->TexCoordSize!=2) {
1187          GLint i, n = VB->Count;
1188          for (i=0;i<n;i++) {
1189             VB->TexCoord[i][2] = 0.0F;
1190             VB->TexCoord[i][3] = 1.0F;
1191          }
1192       }
1193       if (ctx->Current.TexCoord[2]==0.0F && ctx->Current.TexCoord[3]==1.0F) {
1194          VB->TexCoordSize = 2;
1195       }
1196       else {
1197          VB->TexCoordSize = 4;
1198       }
1199    }
1200    else {
1201       /* The vertex buffer was filled but we didn't get a glEnd() call yet
1202        * have to "re-cycle" the vertex buffer.
1203        */
1204       switch (ctx->Primitive) {
1205          case GL_POINTS:
1206             ASSERT(VB->Start==0);
1207             VB->Start = VB->Count = 0;
1208             VB->ClipOrMask = 0;
1209             VB->ClipAndMask = CLIP_ALL_BITS;
1210             VB->MonoMaterial = GL_TRUE;
1211             VB->MonoNormal = GL_TRUE;
1212             break;
1213          case GL_LINES:
1214             ASSERT(VB->Start==0);
1215             VB->Start = VB->Count = 0;
1216             VB->ClipOrMask = 0;
1217             VB->ClipAndMask = CLIP_ALL_BITS;
1218             VB->MonoMaterial = GL_TRUE;
1219             VB->MonoNormal = GL_TRUE;
1220             break;
1221          case GL_LINE_STRIP:
1222             copy_vertex( VB, 0, VB->Count-1 );  /* copy last vertex to front */
1223             VB->Start = VB->Count = 1;
1224             VB->ClipOrMask = VB->ClipMask[0];
1225             VB->ClipAndMask = VB->ClipMask[0];
1226             VB->MonoMaterial = VB->MaterialMask[0] ? GL_FALSE : GL_TRUE;
1227             break;
1228          case GL_LINE_LOOP:
1229             ASSERT(VB->Count==VB_MAX);
1230             copy_vertex( VB, 1, VB_MAX-1 );
1231             VB->Start = VB->Count = 2;
1232             VB->ClipOrMask = VB->ClipMask[0] | VB->ClipMask[1];
1233             VB->ClipAndMask = VB->ClipMask[0] & VB->ClipMask[1];
1234             VB->MonoMaterial = !(VB->MaterialMask[0] | VB->MaterialMask[1]);
1235             break;
1236          case GL_TRIANGLES:
1237             ASSERT(VB->Start==0);
1238             VB->Start = VB->Count = 0;
1239             VB->ClipOrMask = 0;
1240             VB->ClipAndMask = CLIP_ALL_BITS;
1241             VB->MonoMaterial = GL_TRUE;
1242             VB->MonoNormal = GL_TRUE;
1243             break;
1244          case GL_TRIANGLE_STRIP:
1245             copy_vertex( VB, 0, VB_MAX-2 );
1246             copy_vertex( VB, 1, VB_MAX-1 );
1247             VB->Start = VB->Count = 2;
1248             VB->ClipOrMask = VB->ClipMask[0] | VB->ClipMask[1];
1249             VB->ClipAndMask = VB->ClipMask[0] & VB->ClipMask[1];
1250             VB->MonoMaterial = !(VB->MaterialMask[0] | VB->MaterialMask[1]);
1251             break;
1252          case GL_TRIANGLE_FAN:
1253             copy_vertex( VB, 1, VB_MAX-1 );
1254             VB->Start = VB->Count = 2;
1255             VB->ClipOrMask = VB->ClipMask[0] | VB->ClipMask[1];
1256             VB->ClipAndMask = VB->ClipMask[0] & VB->ClipMask[1];
1257             VB->MonoMaterial = !(VB->MaterialMask[0] | VB->MaterialMask[1]);
1258             break;
1259          case GL_QUADS:
1260             ASSERT(VB->Start==0);
1261             VB->Start = VB->Count = 0;
1262             VB->ClipOrMask = 0;
1263             VB->ClipAndMask = CLIP_ALL_BITS;
1264             VB->MonoMaterial = GL_TRUE;
1265             VB->MonoNormal = GL_TRUE;
1266             break;
1267          case GL_QUAD_STRIP:
1268             copy_vertex( VB, 0, VB_MAX-2 );
1269             copy_vertex( VB, 1, VB_MAX-1 );
1270             VB->Start = VB->Count = 2;
1271             VB->ClipOrMask = VB->ClipMask[0] | VB->ClipMask[1];
1272             VB->ClipAndMask = VB->ClipMask[0] & VB->ClipMask[1];
1273             VB->MonoMaterial = !(VB->MaterialMask[0] | VB->MaterialMask[1]);
1274             break;
1275          case GL_POLYGON:
1276             copy_vertex( VB, 1, VB_MAX-1 );
1277             VB->Start = VB->Count = 2;
1278             VB->ClipOrMask = VB->ClipMask[0] | VB->ClipMask[1];
1279             VB->ClipAndMask = VB->ClipMask[0] & VB->ClipMask[1];
1280             VB->MonoMaterial = !(VB->MaterialMask[0] | VB->MaterialMask[1]);
1281             break;
1282          default:
1283             /* should never get here */
1284             gl_problem(ctx, "Bad primitive type in gl_reset_vb()");
1285       }
1286    }
1287 
1288    if (clipOrMask) {
1289       /* reset clip masks to zero */
1290       MEMSET( VB->ClipMask + VB->Start, 0,
1291               (oldCount - VB->Start) * sizeof(VB->ClipMask[0]) );
1292    }
1293 
1294    if (!monoMaterial) {
1295       /* reset material masks to zero */
1296       MEMSET( VB->MaterialMask + VB->Start, 0,
1297               (oldCount - VB->Start) * sizeof(VB->MaterialMask[0]) );
1298       gl_update_lighting(ctx);
1299    }
1300 
1301    if (vertexSizeMask!=VERTEX3_BIT) {
1302       /* reset object W coords to one */
1303       GLint i, n;
1304       GLfloat (*obj)[4] = VB->Obj + VB->Start;
1305       n = oldCount - VB->Start;
1306       for (i=0; i<n; i++) {
1307          obj[i][3] = 1.0F;
1308       }
1309    }
1310 }
1311