2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 * Keith Whitwell <keith@tungstengraphics.com>
29 /* Template for building functions to plug into the driver interface
31 * ctx->Driver.QuadFunc
32 * ctx->Driver.TriangleFunc
33 * ctx->Driver.LineFunc
34 * ctx->Driver.PointsFunc
36 * DO_TWOSIDE: Plug back-color values from the VB into backfacing triangles,
37 * and restore vertices afterwards.
38 * DO_OFFSET: Calculate offset for triangles and adjust vertices. Restore
39 * vertices after rendering.
40 * DO_FLAT: For hardware without native flatshading, copy provoking colors
41 * into the other vertices. Restore after rendering.
42 * DO_UNFILLED: Decompose triangles to lines and points where appropriate.
43 * DO_TWOSTENCIL:Gross hack for two-sided stencil.
45 * HAVE_SPEC: Vertices have secondary rgba values.
47 * VERT_X(v): Alias for vertex x value.
48 * VERT_Y(v): Alias for vertex y value.
49 * VERT_Z(v): Alias for vertex z value.
50 * DEPTH_SCALE: Scale for constant offset.
51 * REVERSE_DEPTH: Viewport depth range reversed.
53 * VERTEX: Hardware vertex type.
54 * GET_VERTEX(n): Retreive vertex with index n.
55 * AREA_IS_CCW(a): Return true if triangle with signed area a is ccw.
57 * VERT_SET_RGBA: Assign vertex rgba from VB color.
58 * VERT_COPY_RGBA: Copy vertex rgba another vertex.
59 * VERT_SAVE_RGBA: Save vertex rgba to a local variable.
60 * VERT_RESTORE_RGBA: Restore vertex rgba from a local variable.
61 * --> Similar for SPEC.
63 * LOCAL_VARS(n): (At least) define local vars for save/restore rgba.
68 #define VERT_SET_RGBA( v, c )
72 #define VERT_SET_SPEC( v, c ) (void) c
73 #define VERT_COPY_SPEC( v0, v1 )
74 #define VERT_SAVE_SPEC( idx )
75 #define VERT_RESTORE_SPEC( idx )
77 #define VERT_COPY_SPEC1( v )
81 #define VERT_SET_SPEC( v, c )
86 #define VERT_COPY_SPEC1( v )
87 #define VERT_COPY_RGBA1( v )
90 #ifndef INSANE_VERTICES
91 #define VERT_SET_Z(v,val) VERT_Z(v) = val
92 #define VERT_Z_ADD(v,val) VERT_Z(v) += val
96 #define REVERSE_DEPTH 0
99 /* disable twostencil for un-aware drivers */
100 #ifndef HAVE_STENCIL_TWOSIDE
101 #define HAVE_STENCIL_TWOSIDE 0
103 #ifndef DO_TWOSTENCIL
104 #define DO_TWOSTENCIL 0
106 #ifndef SETUP_STENCIL
107 #define SETUP_STENCIL(f)
109 #ifndef UNSET_STENCIL
110 #define UNSET_STENCIL(f)
114 static void TAG(triangle)( struct gl_context *ctx, GLuint e0, GLuint e1, GLuint e2 )
116 struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
119 GLfloat z[3] = { 0 };
120 GLenum mode = GL_FILL;
124 /* fprintf(stderr, "%s\n", __FUNCTION__); */
126 v[0] = (VERTEX *)GET_VERTEX(e0);
127 v[1] = (VERTEX *)GET_VERTEX(e1);
128 v[2] = (VERTEX *)GET_VERTEX(e2);
130 if (DO_TWOSIDE || DO_OFFSET || DO_UNFILLED || DO_TWOSTENCIL)
132 GLfloat ex = VERT_X(v[0]) - VERT_X(v[2]);
133 GLfloat ey = VERT_Y(v[0]) - VERT_Y(v[2]);
134 GLfloat fx = VERT_X(v[1]) - VERT_X(v[2]);
135 GLfloat fy = VERT_Y(v[1]) - VERT_Y(v[2]);
136 GLfloat cc = ex*fy - ey*fx;
138 if (DO_TWOSIDE || DO_UNFILLED || DO_TWOSTENCIL)
140 facing = AREA_IS_CCW( cc ) ^ ctx->Polygon._FrontBit;
144 mode = ctx->Polygon.BackMode;
145 if (ctx->Polygon.CullFlag &&
146 ctx->Polygon.CullFaceMode != GL_FRONT) {
150 mode = ctx->Polygon.FrontMode;
151 if (ctx->Polygon.CullFlag &&
152 ctx->Polygon.CullFaceMode != GL_BACK) {
158 if (DO_TWOSIDE && facing == 1) {
159 if (HAVE_BACK_COLORS) {
163 VERT_COPY_RGBA1( v[0] );
164 VERT_COPY_RGBA1( v[1] );
167 VERT_COPY_RGBA1( v[2] );
172 VERT_COPY_SPEC1( v[0] );
173 VERT_COPY_SPEC1( v[1] );
176 VERT_COPY_SPEC1( v[2] );
180 GLfloat (*vbcolor)[4] = VB->BackfaceColorPtr->data;
189 if (VB->BackfaceColorPtr->stride) {
190 ASSERT(VB->BackfaceColorPtr->stride == 4*sizeof(GLfloat));
193 VERT_SET_RGBA( v[0], vbcolor[e0] );
194 VERT_SET_RGBA( v[1], vbcolor[e1] );
196 VERT_SET_RGBA( v[2], vbcolor[e2] );
200 VERT_SET_RGBA( v[0], vbcolor[0] );
201 VERT_SET_RGBA( v[1], vbcolor[0] );
203 VERT_SET_RGBA( v[2], vbcolor[0] );
206 if (HAVE_SPEC && VB->BackfaceSecondaryColorPtr) {
207 GLfloat (*vbspec)[4] = VB->BackfaceSecondaryColorPtr->data;
208 ASSERT(VB->BackfaceSecondaryColorPtr->stride == 4*sizeof(GLfloat));
213 VERT_SET_SPEC( v[0], vbspec[e0] );
214 VERT_SET_SPEC( v[1], vbspec[e1] );
217 VERT_SET_SPEC( v[2], vbspec[e2] );
226 offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
230 if (cc * cc > 1e-16) {
231 GLfloat ic = 1.0 / cc;
232 GLfloat ez = z[0] - z[2];
233 GLfloat fz = z[1] - z[2];
234 GLfloat a = ey*fz - ez*fy;
235 GLfloat b = ez*fx - ex*fz;
238 if ( ac < 0.0f ) ac = -ac;
239 if ( bc < 0.0f ) bc = -bc;
240 offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor / ctx->DrawBuffer->_MRD;
242 offset *= ctx->DrawBuffer->_MRD * (REVERSE_DEPTH ? -1.0 : 1.0);
249 VERT_COPY_RGBA( v[0], v[2] );
250 VERT_COPY_RGBA( v[1], v[2] );
251 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
254 VERT_COPY_SPEC( v[0], v[2] );
255 VERT_COPY_SPEC( v[1], v[2] );
259 if (mode == GL_POINT) {
260 if (DO_OFFSET && ctx->Polygon.OffsetPoint) {
261 VERT_Z_ADD(v[0], offset);
262 VERT_Z_ADD(v[1], offset);
263 VERT_Z_ADD(v[2], offset);
265 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
266 SETUP_STENCIL(facing);
267 UNFILLED_TRI( ctx, GL_POINT, e0, e1, e2 );
268 UNSET_STENCIL(facing);
270 UNFILLED_TRI( ctx, GL_POINT, e0, e1, e2 );
272 } else if (mode == GL_LINE) {
273 if (DO_OFFSET && ctx->Polygon.OffsetLine) {
274 VERT_Z_ADD(v[0], offset);
275 VERT_Z_ADD(v[1], offset);
276 VERT_Z_ADD(v[2], offset);
278 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
279 SETUP_STENCIL(facing);
280 UNFILLED_TRI( ctx, GL_LINE, e0, e1, e2 );
281 UNSET_STENCIL(facing);
283 UNFILLED_TRI( ctx, GL_LINE, e0, e1, e2 );
286 if (DO_OFFSET && ctx->Polygon.OffsetFill) {
287 VERT_Z_ADD(v[0], offset);
288 VERT_Z_ADD(v[1], offset);
289 VERT_Z_ADD(v[2], offset);
292 RASTERIZE( GL_TRIANGLES );
293 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
294 SETUP_STENCIL(facing);
295 TRI( v[0], v[1], v[2] );
296 UNSET_STENCIL(facing);
298 TRI( v[0], v[1], v[2] );
304 VERT_SET_Z(v[0], z[0]);
305 VERT_SET_Z(v[1], z[1]);
306 VERT_SET_Z(v[2], z[2]);
309 if (DO_TWOSIDE && facing == 1) {
311 VERT_RESTORE_RGBA( 0 );
312 VERT_RESTORE_RGBA( 1 );
314 VERT_RESTORE_RGBA( 2 );
317 VERT_RESTORE_SPEC( 0 );
318 VERT_RESTORE_SPEC( 1 );
320 VERT_RESTORE_SPEC( 2 );
326 VERT_RESTORE_RGBA( 0 );
327 VERT_RESTORE_RGBA( 1 );
328 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
329 VERT_RESTORE_SPEC( 0 );
330 VERT_RESTORE_SPEC( 1 );
338 static void TAG(quadr)( struct gl_context *ctx,
339 GLuint e0, GLuint e1, GLuint e2, GLuint e3 )
341 struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
344 GLfloat z[4] = { 0 };
345 GLenum mode = GL_FILL;
349 v[0] = (VERTEX *)GET_VERTEX(e0);
350 v[1] = (VERTEX *)GET_VERTEX(e1);
351 v[2] = (VERTEX *)GET_VERTEX(e2);
352 v[3] = (VERTEX *)GET_VERTEX(e3);
354 if (DO_TWOSIDE || DO_OFFSET || DO_UNFILLED || DO_TWOSTENCIL)
356 GLfloat ex = VERT_X(v[2]) - VERT_X(v[0]);
357 GLfloat ey = VERT_Y(v[2]) - VERT_Y(v[0]);
358 GLfloat fx = VERT_X(v[3]) - VERT_X(v[1]);
359 GLfloat fy = VERT_Y(v[3]) - VERT_Y(v[1]);
360 GLfloat cc = ex*fy - ey*fx;
362 if (DO_TWOSIDE || DO_UNFILLED || DO_TWOSTENCIL)
364 facing = AREA_IS_CCW( cc ) ^ ctx->Polygon._FrontBit;
368 mode = ctx->Polygon.BackMode;
369 if (ctx->Polygon.CullFlag &&
370 ctx->Polygon.CullFaceMode != GL_FRONT) {
374 mode = ctx->Polygon.FrontMode;
375 if (ctx->Polygon.CullFlag &&
376 ctx->Polygon.CullFaceMode != GL_BACK) {
382 if (DO_TWOSIDE && facing == 1) {
383 GLfloat (*vbcolor)[4] = VB->BackfaceColorPtr->data;
386 if (HAVE_BACK_COLORS) {
391 VERT_COPY_RGBA1( v[0] );
392 VERT_COPY_RGBA1( v[1] );
393 VERT_COPY_RGBA1( v[2] );
396 VERT_COPY_RGBA1( v[3] );
402 VERT_COPY_SPEC1( v[0] );
403 VERT_COPY_SPEC1( v[1] );
404 VERT_COPY_SPEC1( v[2] );
407 VERT_COPY_SPEC1( v[3] );
418 if (VB->BackfaceColorPtr->stride) {
420 VERT_SET_RGBA( v[0], vbcolor[e0] );
421 VERT_SET_RGBA( v[1], vbcolor[e1] );
422 VERT_SET_RGBA( v[2], vbcolor[e2] );
424 VERT_SET_RGBA( v[3], vbcolor[e3] );
428 VERT_SET_RGBA( v[0], vbcolor[0] );
429 VERT_SET_RGBA( v[1], vbcolor[0] );
430 VERT_SET_RGBA( v[2], vbcolor[0] );
432 VERT_SET_RGBA( v[3], vbcolor[0] );
435 if (HAVE_SPEC && VB->BackfaceSecondaryColorPtr) {
436 GLfloat (*vbspec)[4] = VB->BackfaceSecondaryColorPtr->data;
437 ASSERT(VB->BackfaceSecondaryColorPtr->stride==4*sizeof(GLfloat));
443 VERT_SET_SPEC( v[0], vbspec[e0] );
444 VERT_SET_SPEC( v[1], vbspec[e1] );
445 VERT_SET_SPEC( v[2], vbspec[e2] );
448 VERT_SET_SPEC( v[3], vbspec[e3] );
457 offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
462 if (cc * cc > 1e-16) {
463 GLfloat ez = z[2] - z[0];
464 GLfloat fz = z[3] - z[1];
465 GLfloat a = ey*fz - ez*fy;
466 GLfloat b = ez*fx - ex*fz;
467 GLfloat ic = 1.0 / cc;
470 if ( ac < 0.0f ) ac = -ac;
471 if ( bc < 0.0f ) bc = -bc;
472 offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor / ctx->DrawBuffer->_MRD;
474 offset *= ctx->DrawBuffer->_MRD * (REVERSE_DEPTH ? -1.0 : 1.0);
482 VERT_COPY_RGBA( v[0], v[3] );
483 VERT_COPY_RGBA( v[1], v[3] );
484 VERT_COPY_RGBA( v[2], v[3] );
485 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
489 VERT_COPY_SPEC( v[0], v[3] );
490 VERT_COPY_SPEC( v[1], v[3] );
491 VERT_COPY_SPEC( v[2], v[3] );
495 if (mode == GL_POINT) {
496 if (( DO_OFFSET) && ctx->Polygon.OffsetPoint) {
497 VERT_Z_ADD(v[0], offset);
498 VERT_Z_ADD(v[1], offset);
499 VERT_Z_ADD(v[2], offset);
500 VERT_Z_ADD(v[3], offset);
502 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
503 SETUP_STENCIL(facing);
504 UNFILLED_QUAD( ctx, GL_POINT, e0, e1, e2, e3 );
505 UNSET_STENCIL(facing);
507 UNFILLED_QUAD( ctx, GL_POINT, e0, e1, e2, e3 );
509 } else if (mode == GL_LINE) {
510 if (DO_OFFSET && ctx->Polygon.OffsetLine) {
511 VERT_Z_ADD(v[0], offset);
512 VERT_Z_ADD(v[1], offset);
513 VERT_Z_ADD(v[2], offset);
514 VERT_Z_ADD(v[3], offset);
516 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
517 SETUP_STENCIL(facing);
518 UNFILLED_QUAD( ctx, GL_LINE, e0, e1, e2, e3 );
519 UNSET_STENCIL(facing);
521 UNFILLED_QUAD( ctx, GL_LINE, e0, e1, e2, e3 );
524 if (DO_OFFSET && ctx->Polygon.OffsetFill) {
525 VERT_Z_ADD(v[0], offset);
526 VERT_Z_ADD(v[1], offset);
527 VERT_Z_ADD(v[2], offset);
528 VERT_Z_ADD(v[3], offset);
530 RASTERIZE( GL_QUADS );
531 if (DO_TWOSTENCIL && !HAVE_STENCIL_TWOSIDE && ctx->Stencil.TestTwoSide) {
532 SETUP_STENCIL(facing);
533 QUAD( (v[0]), (v[1]), (v[2]), (v[3]) );
534 UNSET_STENCIL(facing);
536 QUAD( (v[0]), (v[1]), (v[2]), (v[3]) );
542 VERT_SET_Z(v[0], z[0]);
543 VERT_SET_Z(v[1], z[1]);
544 VERT_SET_Z(v[2], z[2]);
545 VERT_SET_Z(v[3], z[3]);
548 if (DO_TWOSIDE && facing == 1) {
550 VERT_RESTORE_RGBA( 0 );
551 VERT_RESTORE_RGBA( 1 );
552 VERT_RESTORE_RGBA( 2 );
554 VERT_RESTORE_RGBA( 3 );
557 VERT_RESTORE_SPEC( 0 );
558 VERT_RESTORE_SPEC( 1 );
559 VERT_RESTORE_SPEC( 2 );
561 VERT_RESTORE_SPEC( 3 );
567 VERT_RESTORE_RGBA( 0 );
568 VERT_RESTORE_RGBA( 1 );
569 VERT_RESTORE_RGBA( 2 );
570 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
571 VERT_RESTORE_SPEC( 0 );
572 VERT_RESTORE_SPEC( 1 );
573 VERT_RESTORE_SPEC( 2 );
578 static void TAG(quadr)( struct gl_context *ctx, GLuint e0,
579 GLuint e1, GLuint e2, GLuint e3 )
582 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
583 GLubyte ef1 = VB->EdgeFlag[e1];
584 GLubyte ef3 = VB->EdgeFlag[e3];
585 VB->EdgeFlag[e1] = 0;
586 TAG(triangle)( ctx, e0, e1, e3 );
587 VB->EdgeFlag[e1] = ef1;
588 VB->EdgeFlag[e3] = 0;
589 TAG(triangle)( ctx, e1, e2, e3 );
590 VB->EdgeFlag[e3] = ef3;
592 TAG(triangle)( ctx, e0, e1, e3 );
593 TAG(triangle)( ctx, e1, e2, e3 );
600 static void TAG(line)( struct gl_context *ctx, GLuint e0, GLuint e1 )
602 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
606 v[0] = (VERTEX *)GET_VERTEX(e0);
607 v[1] = (VERTEX *)GET_VERTEX(e1);
611 VERT_COPY_RGBA( v[0], v[1] );
612 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
614 VERT_COPY_SPEC( v[0], v[1] );
621 VERT_RESTORE_RGBA( 0 );
623 if (HAVE_SPEC && VB->AttribPtr[_TNL_ATTRIB_COLOR1]) {
624 VERT_RESTORE_SPEC( 0 );
631 static void TAG(points)( struct gl_context *ctx, GLuint first, GLuint last )
633 struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb;
638 for ( i = first ; i < last ; i++ ) {
639 if ( VB->ClipMask[i] == 0 ) {
640 VERTEX *v = (VERTEX *)GET_VERTEX(i);
645 for ( i = first ; i < last ; i++ ) {
646 GLuint e = VB->Elts[i];
647 if ( VB->ClipMask[e] == 0 ) {
648 VERTEX *v = (VERTEX *)GET_VERTEX(e);
656 static void TAG(init)( void )
659 TAB[IND].quad = TAG(quadr);
662 TAB[IND].triangle = TAG(triangle);
665 TAB[IND].line = TAG(line);
668 TAB[IND].points = TAG(points);
681 #undef VERT_COPY_SPEC
682 #undef VERT_SAVE_SPEC
683 #undef VERT_RESTORE_SPEC
685 #undef VERT_COPY_SPEC1
693 #if !HAVE_BACK_COLORS
694 #undef VERT_COPY_SPEC1
695 #undef VERT_COPY_RGBA1
698 #ifndef INSANE_VERTICES