1 /* $Id: vbrender.c,v 1.21 1998/01/18 15:04:48 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-1997 Brian Paul
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.
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.
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.
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)
29 * Revision 1.20 1998/01/09 02:49:33 brianp
30 * cleaned-up gl_reset_vb(), added small GL_POLYGON optimization
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
35 * Revision 1.18 1997/12/19 03:36:42 brianp
36 * check bit-wise AND of vertex clip masks to cull polygons sooner
38 * Revision 1.17 1997/12/09 02:56:57 brianp
39 * in render_clipped_polygon() only recompute window coords for new verts
41 * Revision 1.16 1997/11/20 00:00:47 brianp
42 * only call Driver.RasterSetup() once in render_clipped_polygon()
44 * Revision 1.15 1997/09/18 01:32:47 brianp
45 * fixed divide by zero problem for "weird" projection matrices
47 * Revision 1.14 1997/08/13 01:31:41 brianp
48 * cleaned up code involving LightTwoSide
50 * Revision 1.13 1997/07/24 01:25:27 brianp
51 * changed precompiled header symbol from PCH to PC_HEADER
53 * Revision 1.12 1997/07/11 02:19:52 brianp
54 * flat-shaded quads in a strip were miscolored if clipped (Randy Frank)
56 * Revision 1.11 1997/05/28 03:26:49 brianp
57 * added precompiled header (PCH) support
59 * Revision 1.10 1997/05/16 02:09:26 brianp
60 * clipped GL_TRIANGLE_STRIP triangles sometimes got wrong provoking vertex
62 * Revision 1.9 1997/04/30 02:20:00 brianp
63 * fixed a line clipping bug in GL_LINE_LOOPs
65 * Revision 1.8 1997/04/29 01:31:07 brianp
66 * added RasterSetup() function to device driver
68 * Revision 1.7 1997/04/24 00:30:17 brianp
69 * optimized glTexCoord2() code
71 * Revision 1.6 1997/04/20 19:47:06 brianp
72 * fixed an error message, added a comment
74 * Revision 1.5 1997/04/20 15:59:30 brianp
75 * removed VERTEX2_BIT stuff
77 * Revision 1.4 1997/04/20 15:27:34 brianp
78 * removed odd_flag from all polygon rendering functions
80 * Revision 1.3 1997/04/12 12:26:06 brianp
81 * now directly call ctx->Driver.Points/Line/Triangle/QuadFunc
83 * Revision 1.2 1997/04/07 03:01:11 brianp
84 * optimized vertex[234] code
86 * Revision 1.1 1997/04/02 03:14:14 brianp
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.
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()
116 #include "vbrender.h"
122 * This file implements rendering of points, lines and polygons defined by
123 * vertices in the vertex buffer.
129 # define START_PROFILE \
131 GLdouble t0 = gl_time();
133 # define END_PROFILE( TIMER, COUNTER, INCR ) \
134 TIMER += (gl_time() - t0); \
138 # define START_PROFILE
139 # define END_PROFILE( TIMER, COUNTER, INCR )
146 * Render a line segment from VB[v1] to VB[v2] when either one or both
147 * endpoints must be clipped.
149 static void render_clipped_line( GLcontext
*ctx
, GLuint v1
, GLuint v2
)
151 GLfloat ndc_x
, ndc_y
, ndc_z
;
152 GLuint provoking_vertex
;
153 struct vertex_buffer
*VB
= ctx
->VB
;
155 /* which vertex dictates the color when flat shading: */
156 provoking_vertex
= v2
;
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.
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)
170 /* Apply projection matrix: clip = Proj * eye */
172 TRANSFORM_POINT( VB
->Clip
[v1
], ctx
->ProjectionMatrix
, VB
->Eye
[v1
] );
175 TRANSFORM_POINT( VB
->Clip
[v2
], ctx
->ProjectionMatrix
, VB
->Eye
[v2
] );
179 /* Clip against view volume */
180 if (gl_viewclip_line( ctx
, &v1
, &v2
)==0)
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
;
191 /* Can't divide by zero, so... */
192 ndc_x
= ndc_y
= ndc_z
= 0.0F
;
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
;
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
;
208 /* Can't divide by zero, so... */
209 ndc_x
= ndc_y
= ndc_z
= 0.0F
;
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
;
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 );
224 (*ctx
->Driver
.LineFunc
)( ctx
, v1
, v2
, provoking_vertex
);
225 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
231 * Compute Z offsets for a polygon with plane defined by (A,B,C,D)
234 static void offset_polygon( GLcontext
*ctx
, GLfloat a
, GLfloat b
, GLfloat c
)
239 if (c
<0.001F
&& c
>-0.001F
) {
240 /* to prevent underflow problems */
246 if (ac
<0.0F
) ac
= -ac
;
247 if (bc
<0.0F
) bc
= -bc
;
249 /* m = sqrt( ac*ac + bc*bc ); */
251 offset
= m
* ctx
->Polygon
.OffsetFactor
+ ctx
->Polygon
.OffsetUnits
;
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
;
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.
265 static void unfilled_polygon( GLcontext
*ctx
,
266 GLuint n
, GLuint vlist
[],
267 GLuint pv
, GLuint facing
)
269 GLenum mode
= facing
? ctx
->Polygon
.BackMode
: ctx
->Polygon
.FrontMode
;
270 struct vertex_buffer
*VB
= ctx
->VB
;
272 if (mode
==GL_POINT
) {
276 if ( ctx
->Primitive
==GL_TRIANGLES
277 || ctx
->Primitive
==GL_QUADS
278 || ctx
->Primitive
==GL_POLYGON
) {
287 if (edge
|| VB
->Edgeflag
[j
]) {
288 (*ctx
->Driver
.PointsFunc
)( ctx
, j
, j
);
292 else if (mode
==GL_LINE
) {
296 ctx
->StippleCounter
= 0;
298 if ( ctx
->Primitive
==GL_TRIANGLES
299 || ctx
->Primitive
==GL_QUADS
300 || ctx
->Primitive
==GL_POLYGON
) {
309 j0
= (i
==0) ? vlist
[n
-1] : vlist
[i
-1];
311 if (edge
|| VB
->Edgeflag
[j0
]) {
313 (*ctx
->Driver
.LineFunc
)( ctx
, j0
, j1
, pv
);
314 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
319 /* Fill the polygon */
324 (*ctx
->Driver
.TriangleFunc
)( ctx
, j0
, vlist
[i
-1], vlist
[i
], pv
);
325 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
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.
337 static GLfloat
polygon_area( const struct vertex_buffer
*vb
,
338 GLuint n
, const GLuint vlist
[] )
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! */
353 return area
* 0.5F
; /* divide by two now! */
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.
362 static void render_polygon( GLcontext
*ctx
, GLuint n
, GLuint vlist
[] )
364 struct vertex_buffer
*VB
= ctx
->VB
;
367 /* which vertex dictates the color when flat shading: */
368 pv
= (ctx
->Primitive
==GL_POLYGON
) ? vlist
[0] : vlist
[n
-1];
370 /* Compute orientation of polygon, do cull test, offset, etc */
372 GLuint facing
; /* 0=front, 1=back */
373 GLfloat area
= polygon_area( VB
, n
, vlist
);
376 /* polygon has zero area, don't draw it */
380 facing
= (area
<0.0F
) ^ (ctx
->Polygon
.FrontFace
==GL_CW
);
382 if ((facing
+1) & ctx
->Polygon
.CullBits
) {
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
);
404 if (ctx
->LightTwoSide
) {
406 /* use back color or index */
407 VB
->Color
= VB
->Bcolor
;
408 VB
->Index
= VB
->Bindex
;
411 /* use front color or index */
412 VB
->Color
= VB
->Fcolor
;
413 VB
->Index
= VB
->Findex
;
417 /* Render the polygon! */
418 if (ctx
->Polygon
.Unfilled
) {
419 unfilled_polygon( ctx
, n
, vlist
, pv
, facing
);
422 /* Draw filled polygon as a triangle fan */
424 GLuint j0
= vlist
[0];
427 (*ctx
->Driver
.TriangleFunc
)( ctx
, j0
, vlist
[i
-1], vlist
[i
], pv
);
428 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
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.
442 static void render_clipped_polygon( GLcontext
*ctx
, GLuint n
, GLuint vlist
[] )
445 struct vertex_buffer
*VB
= ctx
->VB
;
446 GLfloat (*win
)[3] = VB
->Win
;
448 /* which vertex dictates the color when flat shading: */
449 pv
= (ctx
->Primitive
==GL_POLYGON
) ? vlist
[0] : vlist
[n
-1];
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.
458 /* Clip against user clipping planes in eye coord space. */
459 if (ctx
->Transform
.AnyClip
) {
460 GLfloat
*proj
= ctx
->ProjectionMatrix
;
462 n
= gl_userclip_polygon( ctx
, n
, vlist
);
465 /* Transform vertices from eye to clip coordinates: clip = Proj * eye */
468 TRANSFORM_POINT( VB
->Clip
[j
], proj
, VB
->Eye
[j
] );
472 /* Clip against view volume in clip coord space */
473 n
= gl_viewclip_polygon( ctx
, n
, vlist
);
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. */
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
;
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
;
498 /* Can't divide by zero, so... */
499 win
[i
][0] = win
[i
][1] = win
[i
][2] = 0.0F
;
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
);
512 if (VB
->ClipMask
[j
]) {
513 /* Uh oh! There should be no clip bits set in final polygon! */
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]);
522 printf("%d %d %02x\n", k
, l
, VB
->ClipMask
[l
]);
530 /* Compute orientation of polygon, do cull test, offset, etc */
532 GLuint facing
; /* 0=front, 1=back */
533 GLfloat area
= polygon_area( VB
, n
, vlist
);
536 /* polygon has zero area, don't draw it */
540 facing
= (area
<0.0F
) ^ (ctx
->Polygon
.FrontFace
==GL_CW
);
542 if ((facing
+1) & ctx
->Polygon
.CullBits
) {
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
);
564 if (ctx
->LightTwoSide
) {
566 /* use back color or index */
567 VB
->Color
= VB
->Bcolor
;
568 VB
->Index
= VB
->Bindex
;
571 /* use front color or index */
572 VB
->Color
= VB
->Fcolor
;
573 VB
->Index
= VB
->Findex
;
577 /* Render the polygon! */
578 if (ctx
->Polygon
.Unfilled
) {
579 unfilled_polygon( ctx
, n
, vlist
, pv
, facing
);
582 /* Draw filled polygon as a triangle fan */
584 GLuint j0
= vlist
[0];
587 (*ctx
->Driver
.TriangleFunc
)( ctx
, j0
, vlist
[i
-1], vlist
[i
], pv
);
588 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
597 * Render an un-clipped triangle.
598 * v0, v1, v2 - vertex indexes. CCW order = front facing
599 * pv - provoking vertex
601 static void render_triangle( GLcontext
*ctx
,
602 GLuint v0
, GLuint v1
, GLuint v2
, GLuint pv
)
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
;
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];
617 /* polygon is perpindicular to view plane, don't draw it */
621 facing
= (c
<0.0F
) ^ (ctx
->Polygon
.FrontFace
==GL_CW
);
623 if ((facing
+1) & ctx
->Polygon
.CullBits
) {
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
);
636 if (ctx
->LightTwoSide
) {
638 /* use back color or index */
639 VB
->Color
= VB
->Bcolor
;
640 VB
->Index
= VB
->Bindex
;
643 /* use front color or index */
644 VB
->Color
= VB
->Fcolor
;
645 VB
->Index
= VB
->Findex
;
649 if (ctx
->Polygon
.Unfilled
) {
654 unfilled_polygon( ctx
, 3, vlist
, pv
, facing
);
658 (*ctx
->Driver
.TriangleFunc
)( ctx
, v0
, v1
, v2
, pv
);
659 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
666 * Render an un-clipped quadrilateral.
667 * v0, v1, v2, v3 : CCW order = front facing
668 * pv - provoking vertex
670 static void render_quad( GLcontext
*ctx
, GLuint v0
, GLuint v1
,
671 GLuint v2
, GLuint v3
, GLuint pv
)
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
;
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];
686 /* polygon is perpindicular to view plane, don't draw it */
690 facing
= (c
<0.0F
) ^ (ctx
->Polygon
.FrontFace
==GL_CW
);
692 if ((facing
+1) & ctx
->Polygon
.CullBits
) {
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
);
705 if (ctx
->LightTwoSide
) {
707 /* use back color or index */
708 VB
->Color
= VB
->Bcolor
;
709 VB
->Index
= VB
->Bindex
;
712 /* use front color or index */
713 VB
->Color
= VB
->Fcolor
;
714 VB
->Index
= VB
->Findex
;
718 /* Render the quad! */
719 if (ctx
->Polygon
.Unfilled
) {
725 unfilled_polygon( ctx
, 4, vlist
, pv
, facing
);
729 (*ctx
->Driver
.QuadFunc
)( ctx
, v0
, v1
, v2
, v3
, pv
);
730 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 2 )
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.
742 static void copy_vertex( struct vertex_buffer
*vb
, GLuint dst
, GLuint src
)
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];
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
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()!
771 * Input: allDone - GL_TRUE = caller is glEnd()
772 * GL_FALSE = calling because buffer is full.
774 void gl_render_vb( GLcontext
*ctx
, GLboolean allDone
)
776 struct vertex_buffer
*VB
= ctx
->VB
;
777 GLuint vlist
[VB_SIZE
];
779 switch (ctx
->Primitive
) {
782 (*ctx
->Driver
.PointsFunc
)( ctx
, 0, VB
->Count
-1 );
783 END_PROFILE( ctx
->PointTime
, ctx
->PointCount
, VB
->Count
)
787 if (VB
->ClipOrMask
) {
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
);
795 (*ctx
->Driver
.LineFunc
)( ctx
, i
-1, i
, i
);
796 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
798 ctx
->StippleCounter
= 0;
803 for (i
=1;i
<VB
->Count
;i
+=2) {
805 (*ctx
->Driver
.LineFunc
)( ctx
, i
-1, i
, i
);
806 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
807 ctx
->StippleCounter
= 0;
813 if (VB
->ClipOrMask
) {
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
);
821 (*ctx
->Driver
.LineFunc
)( ctx
, i
-1, i
, i
);
822 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
827 /* no clipping needed */
829 for (i
=1;i
<VB
->Count
;i
++) {
831 (*ctx
->Driver
.LineFunc
)( ctx
, i
-1, i
, i
);
832 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
841 i
= 1; /* start at 0th vertex */
844 i
= 2; /* skip first vertex, we're saving it until glEnd */
846 while (i
<VB
->Count
) {
847 if (VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
848 render_clipped_line( ctx
, i
-1, i
);
852 (*ctx
->Driver
.LineFunc
)( ctx
, i
-1, i
, i
);
853 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
861 if (VB
->ClipOrMask
) {
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 */
869 else if (VB
->ClipMask
[i
-2] | VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
873 render_clipped_polygon( ctx
, 3, vlist
);
876 if (ctx
->DirectTriangles
) {
878 (*ctx
->Driver
.TriangleFunc
)( ctx
, i
-2, i
-1, i
, i
);
879 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
882 render_triangle( ctx
, i
-2, i
-1, i
, i
);
888 /* no clipping needed */
890 if (ctx
->DirectTriangles
) {
891 for (i
=2;i
<VB
->Count
;i
+=3) {
893 (*ctx
->Driver
.TriangleFunc
)( ctx
, i
-2, i
-1, i
, i
);
894 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
898 for (i
=2;i
<VB
->Count
;i
+=3) {
899 render_triangle( ctx
, i
-2, i
-1, i
, i
);
905 case GL_TRIANGLE_STRIP
:
906 if (VB
->ClipOrMask
) {
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 */
914 else if (VB
->ClipMask
[i
-2] | VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
916 /* reverse vertex order */
920 render_clipped_polygon( ctx
, 3, vlist
);
926 render_clipped_polygon( ctx
, 3, vlist
);
930 if (ctx
->DirectTriangles
) {
932 (*ctx
->Driver
.TriangleFunc
)( ctx
, i
-2, i
-1, i
, i
);
933 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
937 render_triangle( ctx
, i
, i
-1, i
-2, i
);
939 render_triangle( ctx
, i
-2, i
-1, i
, i
);
945 /* no vertices were clipped */
947 if (ctx
->DirectTriangles
) {
948 for (i
=2;i
<VB
->Count
;i
++) {
950 (*ctx
->Driver
.TriangleFunc
)( ctx
, i
-2, i
-1, i
, i
);
951 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
955 for (i
=2;i
<VB
->Count
;i
++) {
957 render_triangle( ctx
, i
, i
-1, i
-2, i
);
959 render_triangle( ctx
, i
-2, i
-1, i
, i
);
965 case GL_TRIANGLE_FAN
:
966 if (VB
->ClipOrMask
) {
968 for (i
=2;i
<VB
->Count
;i
++) {
969 if (VB
->ClipMask
[0] & VB
->ClipMask
[i
-1] & VB
->ClipMask
[i
]
971 /* all points clipped by common plane */
974 else if (VB
->ClipMask
[0] | VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
978 render_clipped_polygon( ctx
, 3, vlist
);
981 if (ctx
->DirectTriangles
) {
983 (*ctx
->Driver
.TriangleFunc
)( ctx
, 0, i
-1, i
, i
);
984 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
987 render_triangle( ctx
, 0, i
-1, i
, i
);
993 /* no clipping needed */
995 if (ctx
->DirectTriangles
) {
996 for (i
=2;i
<VB
->Count
;i
++) {
998 (*ctx
->Driver
.TriangleFunc
)( ctx
, 0, i
-1, i
, i
);
999 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 1 )
1003 for (i
=2;i
<VB
->Count
;i
++) {
1004 render_triangle( ctx
, 0, i
-1, i
, i
);
1011 if (VB
->ClipOrMask
) {
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 */
1019 else if (VB
->ClipMask
[i
-3] | VB
->ClipMask
[i
-2]
1020 | VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
1025 render_clipped_polygon( ctx
, 4, vlist
);
1028 if (ctx
->DirectTriangles
) {
1030 (*ctx
->Driver
.QuadFunc
)( ctx
, i
-3, i
-2, i
-1, i
, i
);
1031 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 2 )
1034 render_quad( ctx
, i
-3, i
-2, i
-1, i
, i
);
1040 /* no vertices were clipped */
1042 if (ctx
->DirectTriangles
) {
1043 for (i
=3;i
<VB
->Count
;i
+=4) {
1045 (*ctx
->Driver
.QuadFunc
)( ctx
, i
-3, i
-2, i
-1, i
, i
);
1046 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 2 )
1050 for (i
=3;i
<VB
->Count
;i
+=4) {
1051 render_quad( ctx
, i
-3, i
-2, i
-1, i
, i
);
1058 if (VB
->ClipOrMask
) {
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 */
1066 else if (VB
->ClipMask
[i
-2] | VB
->ClipMask
[i
-3]
1067 | VB
->ClipMask
[i
-1] | VB
->ClipMask
[i
]) {
1072 render_clipped_polygon( ctx
, 4, vlist
);
1075 if (ctx
->DirectTriangles
) {
1077 (*ctx
->Driver
.QuadFunc
)( ctx
, i
-3, i
-2, i
, i
-1, i
);
1078 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 2 )
1081 render_quad( ctx
, i
-3, i
-2, i
, i
-1, i
);
1087 /* no clipping needed */
1089 if (ctx
->DirectTriangles
) {
1090 for (i
=3;i
<VB
->Count
;i
+=2) {
1092 (*ctx
->Driver
.QuadFunc
)( ctx
, i
-3, i
-2, i
, i
-1, i
);
1093 END_PROFILE( ctx
->PolygonTime
, ctx
->PolygonCount
, 2 )
1097 for (i
=3;i
<VB
->Count
;i
+=2) {
1098 render_quad( ctx
, i
-3, i
-2, i
, i
-1, i
);
1106 if (VB
->ClipAndMask
& CLIP_ALL_BITS
) {
1107 /* all points clipped by common plane, draw nothing */
1110 if (VB
->ClipOrMask
) {
1113 for (i
=0;i
<VB
->Count
;i
++) {
1116 render_clipped_polygon( ctx
, VB
->Count
, vlist
);
1119 /* no clipping needed */
1120 static GLuint const_vlist
[VB_SIZE
];
1121 static GLboolean initFlag
= GL_TRUE
;
1123 /* vertex list always the same, never changes */
1125 for (i
=0;i
<VB_SIZE
;i
++) {
1128 initFlag
= GL_FALSE
;
1130 render_polygon( ctx
, VB
->Count
, const_vlist
);
1136 /* should never get here */
1137 gl_problem( ctx
, "invalid mode in gl_render_vb" );
1140 gl_reset_vb( ctx
, allDone
);
1144 #define CLIP_ALL_BITS 0x3f
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
1155 void gl_reset_vb( GLcontext
*ctx
, GLboolean allDone
)
1157 struct vertex_buffer
*VB
= ctx
->VB
;
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
;
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 );
1172 (*ctx
->Driver
.LineFunc
)( ctx
, VB
->Count
-1, 0, 0 );
1173 END_PROFILE( ctx
->LineTime
, ctx
->LineCount
, 1 )
1178 /* glEnd() was called so reset Vertex Buffer to default, empty state */
1179 VB
->Start
= VB
->Count
= 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
;
1189 VB
->TexCoord
[i
][2] = 0.0F
;
1190 VB
->TexCoord
[i
][3] = 1.0F
;
1193 if (ctx
->Current
.TexCoord
[2]==0.0F
&& ctx
->Current
.TexCoord
[3]==1.0F
) {
1194 VB
->TexCoordSize
= 2;
1197 VB
->TexCoordSize
= 4;
1201 /* The vertex buffer was filled but we didn't get a glEnd() call yet
1202 * have to "re-cycle" the vertex buffer.
1204 switch (ctx
->Primitive
) {
1206 ASSERT(VB
->Start
==0);
1207 VB
->Start
= VB
->Count
= 0;
1209 VB
->ClipAndMask
= CLIP_ALL_BITS
;
1210 VB
->MonoMaterial
= GL_TRUE
;
1211 VB
->MonoNormal
= GL_TRUE
;
1214 ASSERT(VB
->Start
==0);
1215 VB
->Start
= VB
->Count
= 0;
1217 VB
->ClipAndMask
= CLIP_ALL_BITS
;
1218 VB
->MonoMaterial
= GL_TRUE
;
1219 VB
->MonoNormal
= GL_TRUE
;
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
;
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]);
1237 ASSERT(VB
->Start
==0);
1238 VB
->Start
= VB
->Count
= 0;
1240 VB
->ClipAndMask
= CLIP_ALL_BITS
;
1241 VB
->MonoMaterial
= GL_TRUE
;
1242 VB
->MonoNormal
= GL_TRUE
;
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]);
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]);
1260 ASSERT(VB
->Start
==0);
1261 VB
->Start
= VB
->Count
= 0;
1263 VB
->ClipAndMask
= CLIP_ALL_BITS
;
1264 VB
->MonoMaterial
= GL_TRUE
;
1265 VB
->MonoNormal
= GL_TRUE
;
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]);
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]);
1283 /* should never get here */
1284 gl_problem(ctx
, "Bad primitive type in gl_reset_vb()");
1289 /* reset clip masks to zero */
1290 MEMSET( VB
->ClipMask
+ VB
->Start
, 0,
1291 (oldCount
- VB
->Start
) * sizeof(VB
->ClipMask
[0]) );
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
);
1301 if (vertexSizeMask
!=VERTEX3_BIT
) {
1302 /* reset object W coords to one */
1304 GLfloat (*obj
)[4] = VB
->Obj
+ VB
->Start
;
1305 n
= oldCount
- VB
->Start
;
1306 for (i
=0; i
<n
; i
++) {