3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
30 /* Template for building functions to plug into the driver interface
32 * ctx->Driver.QuadFunc
33 * ctx->Driver.TriangleFunc
34 * ctx->Driver.LineFunc
35 * ctx->Driver.PointsFunc
37 * DO_TWOSIDE: Plug back-color values from the VB into backfacing triangles,
38 * and restore vertices afterwards.
39 * DO_OFFSET: Calculate offset for triangles and adjust vertices. Restore
40 * vertices after rendering.
41 * DO_FLAT: For hardware without native flatshading, copy provoking colors
42 * into the other vertices. Restore after rendering.
43 * DO_UNFILLED: Decompose triangles to lines and points where appropriate.
44 * DO_TWOSTENCIL:Gross hack for two-sided stencil.
46 * HAVE_RGBA: Vertices have rgba values (otherwise index values).
47 * HAVE_SPEC: Vertices have secondary rgba values.
49 * VERT_X(v): Alias for vertex x value.
50 * VERT_Y(v): Alias for vertex y value.
51 * VERT_Z(v): Alias for vertex z value.
52 * DEPTH_SCALE: Scale for offset.
54 * VERTEX: Hardware vertex type.
55 * GET_VERTEX(n): Retreive vertex with index n.
56 * AREA_IS_CCW(a): Return true if triangle with signed area a is ccw.
58 * VERT_SET_RGBA: Assign vertex rgba from VB color.
59 * VERT_COPY_RGBA: Copy vertex rgba another vertex.
60 * VERT_SAVE_RGBA: Save vertex rgba to a local variable.
61 * VERT_RESTORE_RGBA: Restore vertex rgba from a local variable.
62 * --> Similar for IND and SPEC.
64 * LOCAL_VARS(n): (At least) define local vars for save/restore rgba.
69 #define VERT_SET_IND( v, c ) (void) c
70 #define VERT_COPY_IND( v0, v1 )
71 #define VERT_SAVE_IND( idx )
72 #define VERT_RESTORE_IND( idx )
74 #define VERT_SET_RGBA( v, c )
77 #define VERT_SET_RGBA( v, c ) (void) c
78 #define VERT_COPY_RGBA( v0, v1 )
79 #define VERT_SAVE_RGBA( idx )
80 #define VERT_RESTORE_RGBA( idx )
82 #define VERT_SET_IND( v, c )
87 #define VERT_SET_SPEC( v, c ) (void) c
88 #define VERT_COPY_SPEC( v0, v1 )
89 #define VERT_SAVE_SPEC( idx )
90 #define VERT_RESTORE_SPEC( idx )
92 #define VERT_COPY_SPEC1( v )
96 #define VERT_SET_SPEC( v, c )
100 #if !HAVE_BACK_COLORS
101 #define VERT_COPY_SPEC1( v )
102 #define VERT_COPY_IND1( v )
103 #define VERT_COPY_RGBA1( v )
106 #ifndef INSANE_VERTICES
107 #define VERT_SET_Z(v,val) VERT_Z(v) = val
108 #define VERT_Z_ADD(v,val) VERT_Z(v) += val
111 /* disable twostencil for un-aware drivers */
112 #ifndef HAVE_STENCIL_TWOSIDE
113 #define HAVE_STENCIL_TWOSIDE 0
115 #ifndef DO_TWOSTENCIL
116 #define DO_TWOSTENCIL 0
118 #ifndef SETUP_STENCIL
119 #define SETUP_STENCIL(f)
121 #ifndef UNSET_STENCIL
122 #define UNSET_STENCIL(f)
126 static void TAG(triangle
)( GLcontext
*ctx
, GLuint e0
, GLuint e1
, GLuint e2
)
128 struct vertex_buffer
*VB
= &TNL_CONTEXT( ctx
)->vb
;
132 GLenum mode
= GL_FILL
;
136 /* fprintf(stderr, "%s\n", __FUNCTION__); */
138 v
[0] = (VERTEX
*)GET_VERTEX(e0
);
139 v
[1] = (VERTEX
*)GET_VERTEX(e1
);
140 v
[2] = (VERTEX
*)GET_VERTEX(e2
);
142 if (DO_TWOSIDE
|| DO_OFFSET
|| DO_UNFILLED
|| DO_TWOSTENCIL
)
144 GLfloat ex
= VERT_X(v
[0]) - VERT_X(v
[2]);
145 GLfloat ey
= VERT_Y(v
[0]) - VERT_Y(v
[2]);
146 GLfloat fx
= VERT_X(v
[1]) - VERT_X(v
[2]);
147 GLfloat fy
= VERT_Y(v
[1]) - VERT_Y(v
[2]);
148 GLfloat cc
= ex
*fy
- ey
*fx
;
150 if (DO_TWOSIDE
|| DO_UNFILLED
|| DO_TWOSTENCIL
)
152 facing
= AREA_IS_CCW( cc
) ^ ctx
->Polygon
._FrontBit
;
154 if (DO_TWOSTENCIL
&& ctx
->Stencil
.TestTwoSide
) {
155 ctx
->_Facing
= facing
; /* mixed mode rendering: for 2-sided stencil test */
160 mode
= ctx
->Polygon
.BackMode
;
161 if (ctx
->Polygon
.CullFlag
&&
162 ctx
->Polygon
.CullFaceMode
!= GL_FRONT
) {
166 mode
= ctx
->Polygon
.FrontMode
;
167 if (ctx
->Polygon
.CullFlag
&&
168 ctx
->Polygon
.CullFaceMode
!= GL_BACK
) {
174 if (DO_TWOSIDE
&& facing
== 1)
177 if (HAVE_BACK_COLORS
) {
181 VERT_COPY_RGBA1( v
[0] );
182 VERT_COPY_RGBA1( v
[1] );
185 VERT_COPY_RGBA1( v
[2] );
190 VERT_COPY_SPEC1( v
[0] );
191 VERT_COPY_SPEC1( v
[1] );
194 VERT_COPY_SPEC1( v
[2] );
198 GLfloat (*vbcolor
)[4] = VB
->ColorPtr
[1]->data
;
199 ASSERT(VB
->ColorPtr
[1]->stride
== 4*sizeof(GLfloat
));
205 VERT_SET_RGBA( v
[0], vbcolor
[e0
] );
206 VERT_SET_RGBA( v
[1], vbcolor
[e1
] );
209 VERT_SET_RGBA( v
[2], vbcolor
[e2
] );
211 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[1]) {
212 GLfloat (*vbspec
)[4] = VB
->SecondaryColorPtr
[1]->data
;
217 VERT_SET_SPEC( v
[0], vbspec
[e0
] );
218 VERT_SET_SPEC( v
[1], vbspec
[e1
] );
221 VERT_SET_SPEC( v
[2], vbspec
[e2
] );
226 GLfloat (*vbindex
) = (GLfloat
*)VB
->IndexPtr
[1]->data
;
230 VERT_SET_IND( v
[0], vbindex
[e0
] );
231 VERT_SET_IND( v
[1], vbindex
[e1
] );
234 VERT_SET_IND( v
[2], vbindex
[e2
] );
242 offset
= ctx
->Polygon
.OffsetUnits
* DEPTH_SCALE
;
246 if (cc
* cc
> 1e-16) {
247 GLfloat ic
= 1.0 / cc
;
248 GLfloat ez
= z
[0] - z
[2];
249 GLfloat fz
= z
[1] - z
[2];
250 GLfloat a
= ey
*fz
- ez
*fy
;
251 GLfloat b
= ez
*fx
- ex
*fz
;
254 if ( ac
< 0.0f
) ac
= -ac
;
255 if ( bc
< 0.0f
) bc
= -bc
;
256 offset
+= MAX2( ac
, bc
) * ctx
->Polygon
.OffsetFactor
;
266 VERT_COPY_RGBA( v
[0], v
[2] );
267 VERT_COPY_RGBA( v
[1], v
[2] );
268 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
271 VERT_COPY_SPEC( v
[0], v
[2] );
272 VERT_COPY_SPEC( v
[1], v
[2] );
278 VERT_COPY_IND( v
[0], v
[2] );
279 VERT_COPY_IND( v
[1], v
[2] );
283 if (mode
== GL_POINT
) {
284 if (DO_OFFSET
&& ctx
->Polygon
.OffsetPoint
) {
285 VERT_Z_ADD(v
[0], offset
);
286 VERT_Z_ADD(v
[1], offset
);
287 VERT_Z_ADD(v
[2], offset
);
289 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
290 SETUP_STENCIL(facing
);
291 UNFILLED_TRI( ctx
, GL_POINT
, e0
, e1
, e2
);
292 UNSET_STENCIL(facing
);
294 UNFILLED_TRI( ctx
, GL_POINT
, e0
, e1
, e2
);
296 } else if (mode
== GL_LINE
) {
297 if (DO_OFFSET
&& ctx
->Polygon
.OffsetLine
) {
298 VERT_Z_ADD(v
[0], offset
);
299 VERT_Z_ADD(v
[1], offset
);
300 VERT_Z_ADD(v
[2], offset
);
302 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
303 SETUP_STENCIL(facing
);
304 UNFILLED_TRI( ctx
, GL_LINE
, e0
, e1
, e2
);
305 UNSET_STENCIL(facing
);
307 UNFILLED_TRI( ctx
, GL_LINE
, e0
, e1
, e2
);
310 if (DO_OFFSET
&& ctx
->Polygon
.OffsetFill
) {
311 VERT_Z_ADD(v
[0], offset
);
312 VERT_Z_ADD(v
[1], offset
);
313 VERT_Z_ADD(v
[2], offset
);
316 RASTERIZE( GL_TRIANGLES
);
317 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
318 SETUP_STENCIL(facing
);
319 TRI( v
[0], v
[1], v
[2] );
320 UNSET_STENCIL(facing
);
322 TRI( v
[0], v
[1], v
[2] );
328 VERT_SET_Z(v
[0], z
[0]);
329 VERT_SET_Z(v
[1], z
[1]);
330 VERT_SET_Z(v
[2], z
[2]);
333 if (DO_TWOSIDE
&& facing
== 1)
337 VERT_RESTORE_RGBA( 0 );
338 VERT_RESTORE_RGBA( 1 );
340 VERT_RESTORE_RGBA( 2 );
343 VERT_RESTORE_SPEC( 0 );
344 VERT_RESTORE_SPEC( 1 );
346 VERT_RESTORE_SPEC( 2 );
351 VERT_RESTORE_IND( 0 );
352 VERT_RESTORE_IND( 1 );
354 VERT_RESTORE_IND( 2 );
361 VERT_RESTORE_RGBA( 0 );
362 VERT_RESTORE_RGBA( 1 );
363 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
364 VERT_RESTORE_SPEC( 0 );
365 VERT_RESTORE_SPEC( 1 );
369 VERT_RESTORE_IND( 0 );
370 VERT_RESTORE_IND( 1 );
378 static void TAG(quad
)( GLcontext
*ctx
,
379 GLuint e0
, GLuint e1
, GLuint e2
, GLuint e3
)
381 struct vertex_buffer
*VB
= &TNL_CONTEXT( ctx
)->vb
;
385 GLenum mode
= GL_FILL
;
389 v
[0] = (VERTEX
*)GET_VERTEX(e0
);
390 v
[1] = (VERTEX
*)GET_VERTEX(e1
);
391 v
[2] = (VERTEX
*)GET_VERTEX(e2
);
392 v
[3] = (VERTEX
*)GET_VERTEX(e3
);
394 if (DO_TWOSIDE
|| DO_OFFSET
|| DO_UNFILLED
|| DO_TWOSTENCIL
)
396 GLfloat ex
= VERT_X(v
[2]) - VERT_X(v
[0]);
397 GLfloat ey
= VERT_Y(v
[2]) - VERT_Y(v
[0]);
398 GLfloat fx
= VERT_X(v
[3]) - VERT_X(v
[1]);
399 GLfloat fy
= VERT_Y(v
[3]) - VERT_Y(v
[1]);
400 GLfloat cc
= ex
*fy
- ey
*fx
;
402 if (DO_TWOSIDE
|| DO_UNFILLED
|| DO_TWOSTENCIL
)
404 facing
= AREA_IS_CCW( cc
) ^ ctx
->Polygon
._FrontBit
;
406 if (DO_TWOSTENCIL
&& ctx
->Stencil
.TestTwoSide
) {
407 ctx
->_Facing
= facing
; /* mixed mode rendering: for 2-sided stencil test */
412 mode
= ctx
->Polygon
.BackMode
;
413 if (ctx
->Polygon
.CullFlag
&&
414 ctx
->Polygon
.CullFaceMode
!= GL_FRONT
) {
418 mode
= ctx
->Polygon
.FrontMode
;
419 if (ctx
->Polygon
.CullFlag
&&
420 ctx
->Polygon
.CullFaceMode
!= GL_BACK
) {
426 if (DO_TWOSIDE
&& facing
== 1)
429 GLfloat (*vbcolor
)[4] = VB
->ColorPtr
[1]->data
;
432 if (HAVE_BACK_COLORS
) {
437 VERT_COPY_RGBA1( v
[0] );
438 VERT_COPY_RGBA1( v
[1] );
439 VERT_COPY_RGBA1( v
[2] );
442 VERT_COPY_RGBA1( v
[3] );
448 VERT_COPY_SPEC1( v
[0] );
449 VERT_COPY_SPEC1( v
[1] );
450 VERT_COPY_SPEC1( v
[2] );
453 VERT_COPY_SPEC1( v
[3] );
461 VERT_SET_RGBA( v
[0], vbcolor
[e0
] );
462 VERT_SET_RGBA( v
[1], vbcolor
[e1
] );
463 VERT_SET_RGBA( v
[2], vbcolor
[e2
] );
466 VERT_SET_RGBA( v
[3], vbcolor
[e3
] );
468 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[1]) {
469 GLfloat (*vbspec
)[4] = VB
->SecondaryColorPtr
[1]->data
;
470 ASSERT(VB
->SecondaryColorPtr
[1]->stride
==4*sizeof(GLfloat
));
476 VERT_SET_SPEC( v
[0], vbspec
[e0
] );
477 VERT_SET_SPEC( v
[1], vbspec
[e1
] );
478 VERT_SET_SPEC( v
[2], vbspec
[e2
] );
481 VERT_SET_SPEC( v
[3], vbspec
[e3
] );
486 GLfloat
*vbindex
= (GLfloat
*)VB
->IndexPtr
[1]->data
;
491 VERT_SET_IND( v
[0], vbindex
[e0
] );
492 VERT_SET_IND( v
[1], vbindex
[e1
] );
493 VERT_SET_IND( v
[2], vbindex
[e2
] );
496 VERT_SET_IND( v
[3], vbindex
[e3
] );
504 offset
= ctx
->Polygon
.OffsetUnits
* DEPTH_SCALE
;
509 if (cc
* cc
> 1e-16) {
510 GLfloat ez
= z
[2] - z
[0];
511 GLfloat fz
= z
[3] - z
[1];
512 GLfloat a
= ey
*fz
- ez
*fy
;
513 GLfloat b
= ez
*fx
- ex
*fz
;
514 GLfloat ic
= 1.0 / cc
;
517 if ( ac
< 0.0f
) ac
= -ac
;
518 if ( bc
< 0.0f
) bc
= -bc
;
519 offset
+= MAX2( ac
, bc
) * ctx
->Polygon
.OffsetFactor
;
530 VERT_COPY_RGBA( v
[0], v
[3] );
531 VERT_COPY_RGBA( v
[1], v
[3] );
532 VERT_COPY_RGBA( v
[2], v
[3] );
533 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
537 VERT_COPY_SPEC( v
[0], v
[3] );
538 VERT_COPY_SPEC( v
[1], v
[3] );
539 VERT_COPY_SPEC( v
[2], v
[3] );
546 VERT_COPY_IND( v
[0], v
[3] );
547 VERT_COPY_IND( v
[1], v
[3] );
548 VERT_COPY_IND( v
[2], v
[3] );
552 if (mode
== GL_POINT
) {
553 if (( DO_OFFSET
) && ctx
->Polygon
.OffsetPoint
) {
554 VERT_Z_ADD(v
[0], offset
);
555 VERT_Z_ADD(v
[1], offset
);
556 VERT_Z_ADD(v
[2], offset
);
557 VERT_Z_ADD(v
[3], offset
);
559 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
560 SETUP_STENCIL(facing
);
561 UNFILLED_QUAD( ctx
, GL_POINT
, e0
, e1
, e2
, e3
);
562 UNSET_STENCIL(facing
);
564 UNFILLED_QUAD( ctx
, GL_POINT
, e0
, e1
, e2
, e3
);
566 } else if (mode
== GL_LINE
) {
567 if (DO_OFFSET
&& ctx
->Polygon
.OffsetLine
) {
568 VERT_Z_ADD(v
[0], offset
);
569 VERT_Z_ADD(v
[1], offset
);
570 VERT_Z_ADD(v
[2], offset
);
571 VERT_Z_ADD(v
[3], offset
);
573 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
574 SETUP_STENCIL(facing
);
575 UNFILLED_QUAD( ctx
, GL_LINE
, e0
, e1
, e2
, e3
);
576 UNSET_STENCIL(facing
);
578 UNFILLED_QUAD( ctx
, GL_LINE
, e0
, e1
, e2
, e3
);
581 if (DO_OFFSET
&& ctx
->Polygon
.OffsetFill
) {
582 VERT_Z_ADD(v
[0], offset
);
583 VERT_Z_ADD(v
[1], offset
);
584 VERT_Z_ADD(v
[2], offset
);
585 VERT_Z_ADD(v
[3], offset
);
587 RASTERIZE( GL_TRIANGLES
);
588 if (DO_TWOSTENCIL
&& !HAVE_STENCIL_TWOSIDE
&& ctx
->Stencil
.TestTwoSide
) {
589 SETUP_STENCIL(facing
);
590 QUAD( (v
[0]), (v
[1]), (v
[2]), (v
[3]) );
591 UNSET_STENCIL(facing
);
593 QUAD( (v
[0]), (v
[1]), (v
[2]), (v
[3]) );
599 VERT_SET_Z(v
[0], z
[0]);
600 VERT_SET_Z(v
[1], z
[1]);
601 VERT_SET_Z(v
[2], z
[2]);
602 VERT_SET_Z(v
[3], z
[3]);
605 if (DO_TWOSIDE
&& facing
== 1)
609 VERT_RESTORE_RGBA( 0 );
610 VERT_RESTORE_RGBA( 1 );
611 VERT_RESTORE_RGBA( 2 );
613 VERT_RESTORE_RGBA( 3 );
616 VERT_RESTORE_SPEC( 0 );
617 VERT_RESTORE_SPEC( 1 );
618 VERT_RESTORE_SPEC( 2 );
620 VERT_RESTORE_SPEC( 3 );
625 VERT_RESTORE_IND( 0 );
626 VERT_RESTORE_IND( 1 );
627 VERT_RESTORE_IND( 2 );
629 VERT_RESTORE_IND( 3 );
636 VERT_RESTORE_RGBA( 0 );
637 VERT_RESTORE_RGBA( 1 );
638 VERT_RESTORE_RGBA( 2 );
639 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
640 VERT_RESTORE_SPEC( 0 );
641 VERT_RESTORE_SPEC( 1 );
642 VERT_RESTORE_SPEC( 2 );
646 VERT_RESTORE_IND( 0 );
647 VERT_RESTORE_IND( 1 );
648 VERT_RESTORE_IND( 2 );
653 static void TAG(quad
)( GLcontext
*ctx
, GLuint e0
,
654 GLuint e1
, GLuint e2
, GLuint e3
)
657 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
658 GLubyte ef1
= VB
->EdgeFlag
[e1
];
659 GLubyte ef3
= VB
->EdgeFlag
[e3
];
660 VB
->EdgeFlag
[e1
] = 0;
661 TAG(triangle
)( ctx
, e0
, e1
, e3
);
662 VB
->EdgeFlag
[e1
] = ef1
;
663 VB
->EdgeFlag
[e3
] = 0;
664 TAG(triangle
)( ctx
, e1
, e2
, e3
);
665 VB
->EdgeFlag
[e3
] = ef3
;
667 TAG(triangle
)( ctx
, e0
, e1
, e3
);
668 TAG(triangle
)( ctx
, e1
, e2
, e3
);
675 static void TAG(line
)( GLcontext
*ctx
, GLuint e0
, GLuint e1
)
677 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
681 v
[0] = (VERTEX
*)GET_VERTEX(e0
);
682 v
[1] = (VERTEX
*)GET_VERTEX(e1
);
687 VERT_COPY_RGBA( v
[0], v
[1] );
688 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
690 VERT_COPY_SPEC( v
[0], v
[1] );
695 VERT_COPY_IND( v
[0], v
[1] );
703 VERT_RESTORE_RGBA( 0 );
705 if (HAVE_SPEC
&& VB
->SecondaryColorPtr
[0]) {
706 VERT_RESTORE_SPEC( 0 );
710 VERT_RESTORE_IND( 0 );
717 static void TAG(points
)( GLcontext
*ctx
, GLuint first
, GLuint last
)
719 struct vertex_buffer
*VB
= &TNL_CONTEXT( ctx
)->vb
;
724 for ( i
= first
; i
< last
; i
++ ) {
725 if ( VB
->ClipMask
[i
] == 0 ) {
726 VERTEX
*v
= (VERTEX
*)GET_VERTEX(i
);
731 for ( i
= first
; i
< last
; i
++ ) {
732 GLuint e
= VB
->Elts
[i
];
733 if ( VB
->ClipMask
[e
] == 0 ) {
734 VERTEX
*v
= (VERTEX
*)GET_VERTEX(e
);
742 static void TAG(init
)( void )
745 TAB
[IND
].quad
= TAG(quad
);
748 TAB
[IND
].triangle
= TAG(triangle
);
751 TAB
[IND
].line
= TAG(line
);
754 TAB
[IND
].points
= TAG(points
);
765 #undef VERT_RESTORE_IND
771 #undef VERT_COPY_RGBA
772 #undef VERT_SAVE_RGBA
773 #undef VERT_RESTORE_RGBA
781 #undef VERT_COPY_SPEC
782 #undef VERT_SAVE_SPEC
783 #undef VERT_RESTORE_SPEC
785 #undef VERT_COPY_SPEC1
793 #if !HAVE_BACK_COLORS
794 #undef VERT_COPY_SPEC1
795 #undef VERT_COPY_IND1
796 #undef VERT_COPY_RGBA1
799 #ifndef INSANE_VERTICES