s_aatritemp.h revision 77df88727cb0a423dd5cb41498c2302d9df4fce7
1/* $Id: s_aatritemp.h,v 1.30 2002/08/07 00:45:07 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/*
29 * Antialiased Triangle Rasterizer Template
30 *
31 * This file is #include'd to generate custom AA triangle rasterizers.
32 * NOTE: this code hasn't been optimized yet.  That'll come after it
33 * works correctly.
34 *
35 * The following macros may be defined to indicate what auxillary information
36 * must be copmuted across the triangle:
37 *    DO_Z         - if defined, compute Z values
38 *    DO_RGBA      - if defined, compute RGBA values
39 *    DO_INDEX     - if defined, compute color index values
40 *    DO_SPEC      - if defined, compute specular RGB values
41 *    DO_TEX       - if defined, compute unit 0 STRQ texcoords
42 *    DO_MULTITEX  - if defined, compute all unit's STRQ texcoords
43 */
44
45/*void triangle( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
46{
47   const GLfloat *p0 = v0->win;
48   const GLfloat *p1 = v1->win;
49   const GLfloat *p2 = v2->win;
50   const SWvertex *vMin, *vMid, *vMax;
51   GLint iyMin, iyMax;
52   GLfloat yMin, yMax;
53   GLboolean ltor;
54   GLfloat majDx, majDy;  /* major (i.e. long) edge dx and dy */
55
56   struct sw_span span;
57
58#ifdef DO_Z
59   GLfloat zPlane[4];
60#endif
61#ifdef DO_FOG
62   GLfloat fogPlane[4];
63#else
64   GLfloat *fog = NULL;
65#endif
66#ifdef DO_RGBA
67   GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
68#endif
69#ifdef DO_INDEX
70   GLfloat iPlane[4];
71#endif
72#ifdef DO_SPEC
73   GLfloat srPlane[4], sgPlane[4], sbPlane[4];
74#endif
75#ifdef DO_TEX
76   GLfloat sPlane[4], tPlane[4], uPlane[4], vPlane[4];
77   GLfloat texWidth, texHeight;
78#elif defined(DO_MULTITEX)
79   GLfloat sPlane[MAX_TEXTURE_UNITS][4];  /* texture S */
80   GLfloat tPlane[MAX_TEXTURE_UNITS][4];  /* texture T */
81   GLfloat uPlane[MAX_TEXTURE_UNITS][4];  /* texture R */
82   GLfloat vPlane[MAX_TEXTURE_UNITS][4];  /* texture Q */
83   GLfloat texWidth[MAX_TEXTURE_UNITS], texHeight[MAX_TEXTURE_UNITS];
84#endif
85   GLfloat bf = SWRAST_CONTEXT(ctx)->_backface_sign;
86
87
88   INIT_SPAN(span, GL_POLYGON, 0, 0, SPAN_COVERAGE);
89
90   /* determine bottom to top order of vertices */
91   {
92      GLfloat y0 = v0->win[1];
93      GLfloat y1 = v1->win[1];
94      GLfloat y2 = v2->win[1];
95      if (y0 <= y1) {
96	 if (y1 <= y2) {
97	    vMin = v0;   vMid = v1;   vMax = v2;   /* y0<=y1<=y2 */
98	 }
99	 else if (y2 <= y0) {
100	    vMin = v2;   vMid = v0;   vMax = v1;   /* y2<=y0<=y1 */
101	 }
102	 else {
103	    vMin = v0;   vMid = v2;   vMax = v1;  bf = -bf; /* y0<=y2<=y1 */
104	 }
105      }
106      else {
107	 if (y0 <= y2) {
108	    vMin = v1;   vMid = v0;   vMax = v2;  bf = -bf; /* y1<=y0<=y2 */
109	 }
110	 else if (y2 <= y1) {
111	    vMin = v2;   vMid = v1;   vMax = v0;  bf = -bf; /* y2<=y1<=y0 */
112	 }
113	 else {
114	    vMin = v1;   vMid = v2;   vMax = v0;   /* y1<=y2<=y0 */
115	 }
116      }
117   }
118
119   majDx = vMax->win[0] - vMin->win[0];
120   majDy = vMax->win[1] - vMin->win[1];
121
122   {
123      const GLfloat botDx = vMid->win[0] - vMin->win[0];
124      const GLfloat botDy = vMid->win[1] - vMin->win[1];
125      const GLfloat area = majDx * botDy - botDx * majDy;
126      ltor = (GLboolean) (area < 0.0F);
127      /* Do backface culling */
128      if (area * bf < 0 || area == 0 || IS_INF_OR_NAN(area))
129	 return;
130   }
131
132#ifndef DO_OCCLUSION_TEST
133   ctx->OcclusionResult = GL_TRUE;
134#endif
135
136   /* Plane equation setup:
137    * We evaluate plane equations at window (x,y) coordinates in order
138    * to compute color, Z, fog, texcoords, etc.  This isn't terribly
139    * efficient but it's easy and reliable.
140    */
141#ifdef DO_Z
142   compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
143   span.arrayMask |= SPAN_Z;
144#endif
145#ifdef DO_FOG
146   compute_plane(p0, p1, p2, v0->fog, v1->fog, v2->fog, fogPlane);
147   span.arrayMask |= SPAN_FOG;
148#endif
149#ifdef DO_RGBA
150   if (ctx->Light.ShadeModel == GL_SMOOTH) {
151      compute_plane(p0, p1, p2, v0->color[0], v1->color[0], v2->color[0], rPlane);
152      compute_plane(p0, p1, p2, v0->color[1], v1->color[1], v2->color[1], gPlane);
153      compute_plane(p0, p1, p2, v0->color[2], v1->color[2], v2->color[2], bPlane);
154      compute_plane(p0, p1, p2, v0->color[3], v1->color[3], v2->color[3], aPlane);
155   }
156   else {
157      constant_plane(v2->color[RCOMP], rPlane);
158      constant_plane(v2->color[GCOMP], gPlane);
159      constant_plane(v2->color[BCOMP], bPlane);
160      constant_plane(v2->color[ACOMP], aPlane);
161   }
162   span.arrayMask |= SPAN_RGBA;
163#endif
164#ifdef DO_INDEX
165   if (ctx->Light.ShadeModel == GL_SMOOTH) {
166      compute_plane(p0, p1, p2, (GLfloat) v0->index,
167                    (GLfloat) v1->index, (GLfloat) v2->index, iPlane);
168   }
169   else {
170      constant_plane((GLfloat) v2->index, iPlane);
171   }
172   span.arrayMask |= SPAN_INDEX;
173#endif
174#ifdef DO_SPEC
175   if (ctx->Light.ShadeModel == GL_SMOOTH) {
176      compute_plane(p0, p1, p2, v0->specular[0], v1->specular[0], v2->specular[0],srPlane);
177      compute_plane(p0, p1, p2, v0->specular[1], v1->specular[1], v2->specular[1],sgPlane);
178      compute_plane(p0, p1, p2, v0->specular[2], v1->specular[2], v2->specular[2],sbPlane);
179   }
180   else {
181      constant_plane(v2->specular[RCOMP], srPlane);
182      constant_plane(v2->specular[GCOMP], sgPlane);
183      constant_plane(v2->specular[BCOMP], sbPlane);
184   }
185   span.arrayMask |= SPAN_SPEC;
186#endif
187#ifdef DO_TEX
188   {
189      const struct gl_texture_object *obj = ctx->Texture.Unit[0]._Current;
190      const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];
191      const GLfloat invW0 = v0->win[3];
192      const GLfloat invW1 = v1->win[3];
193      const GLfloat invW2 = v2->win[3];
194      const GLfloat s0 = v0->texcoord[0][0] * invW0;
195      const GLfloat s1 = v1->texcoord[0][0] * invW1;
196      const GLfloat s2 = v2->texcoord[0][0] * invW2;
197      const GLfloat t0 = v0->texcoord[0][1] * invW0;
198      const GLfloat t1 = v1->texcoord[0][1] * invW1;
199      const GLfloat t2 = v2->texcoord[0][1] * invW2;
200      const GLfloat r0 = v0->texcoord[0][2] * invW0;
201      const GLfloat r1 = v1->texcoord[0][2] * invW1;
202      const GLfloat r2 = v2->texcoord[0][2] * invW2;
203      const GLfloat q0 = v0->texcoord[0][3] * invW0;
204      const GLfloat q1 = v1->texcoord[0][3] * invW1;
205      const GLfloat q2 = v2->texcoord[0][3] * invW2;
206      compute_plane(p0, p1, p2, s0, s1, s2, sPlane);
207      compute_plane(p0, p1, p2, t0, t1, t2, tPlane);
208      compute_plane(p0, p1, p2, r0, r1, r2, uPlane);
209      compute_plane(p0, p1, p2, q0, q1, q2, vPlane);
210      texWidth = (GLfloat) texImage->Width;
211      texHeight = (GLfloat) texImage->Height;
212   }
213   span.arrayMask |= (SPAN_TEXTURE | SPAN_LAMBDA);
214#elif defined(DO_MULTITEX)
215   {
216      GLuint u;
217      for (u = 0; u < ctx->Const.MaxTextureUnits; u++) {
218         if (ctx->Texture.Unit[u]._ReallyEnabled) {
219            const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
220            const struct gl_texture_image *texImage = obj->Image[obj->BaseLevel];
221            const GLfloat invW0 = v0->win[3];
222            const GLfloat invW1 = v1->win[3];
223            const GLfloat invW2 = v2->win[3];
224            const GLfloat s0 = v0->texcoord[u][0] * invW0;
225            const GLfloat s1 = v1->texcoord[u][0] * invW1;
226            const GLfloat s2 = v2->texcoord[u][0] * invW2;
227            const GLfloat t0 = v0->texcoord[u][1] * invW0;
228            const GLfloat t1 = v1->texcoord[u][1] * invW1;
229            const GLfloat t2 = v2->texcoord[u][1] * invW2;
230            const GLfloat r0 = v0->texcoord[u][2] * invW0;
231            const GLfloat r1 = v1->texcoord[u][2] * invW1;
232            const GLfloat r2 = v2->texcoord[u][2] * invW2;
233            const GLfloat q0 = v0->texcoord[u][3] * invW0;
234            const GLfloat q1 = v1->texcoord[u][3] * invW1;
235            const GLfloat q2 = v2->texcoord[u][3] * invW2;
236            compute_plane(p0, p1, p2, s0, s1, s2, sPlane[u]);
237            compute_plane(p0, p1, p2, t0, t1, t2, tPlane[u]);
238            compute_plane(p0, p1, p2, r0, r1, r2, uPlane[u]);
239            compute_plane(p0, p1, p2, q0, q1, q2, vPlane[u]);
240            texWidth[u]  = (GLfloat) texImage->Width;
241            texHeight[u] = (GLfloat) texImage->Height;
242         }
243      }
244   }
245   span.arrayMask |= (SPAN_TEXTURE | SPAN_LAMBDA);
246#endif
247
248   /* Begin bottom-to-top scan over the triangle.
249    * The long edge will either be on the left or right side of the
250    * triangle.  We always scan from the long edge toward the shorter
251    * edges, stopping when we find that coverage = 0.  If the long edge
252    * is on the left we scan left-to-right.  Else, we scan right-to-left.
253    */
254   yMin = vMin->win[1];
255   yMax = vMax->win[1];
256   iyMin = (GLint) yMin;
257   iyMax = (GLint) yMax + 1;
258
259   if (ltor) {
260      /* scan left to right */
261      const GLfloat *pMin = vMin->win;
262      const GLfloat *pMid = vMid->win;
263      const GLfloat *pMax = vMax->win;
264      const GLfloat dxdy = majDx / majDy;
265      const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
266      GLfloat x = pMin[0] - (yMin - iyMin) * dxdy;
267      GLint iy;
268      for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
269         GLint ix, startX = (GLint) (x - xAdj);
270         GLuint count;
271         GLfloat coverage = 0.0F;
272
273         /* skip over fragments with zero coverage */
274         while (startX < MAX_WIDTH) {
275            coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
276            if (coverage > 0.0F)
277               break;
278            startX++;
279         }
280
281         /* enter interior of triangle */
282         ix = startX;
283         count = 0;
284         while (coverage > 0.0F) {
285            /* (cx,cy) = center of fragment */
286            const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
287            struct span_arrays *array = span.array;
288#ifdef DO_INDEX
289            array->coverage[count] = (GLfloat) compute_coveragei(pMin, pMid, pMax, ix, iy);
290#else
291            array->coverage[count] = coverage;
292#endif
293#ifdef DO_Z
294            array->z[count] = (GLdepth) solve_plane(cx, cy, zPlane);
295#endif
296#ifdef DO_FOG
297	    array->fog[count] = solve_plane(cx, cy, fogPlane);
298#endif
299#ifdef DO_RGBA
300            array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane);
301            array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane);
302            array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane);
303            array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane);
304#endif
305#ifdef DO_INDEX
306            array->index[count] = (GLint) solve_plane(cx, cy, iPlane);
307#endif
308#ifdef DO_SPEC
309            array->spec[count][RCOMP] = solve_plane_chan(cx, cy, srPlane);
310            array->spec[count][GCOMP] = solve_plane_chan(cx, cy, sgPlane);
311            array->spec[count][BCOMP] = solve_plane_chan(cx, cy, sbPlane);
312#endif
313#ifdef DO_TEX
314            {
315               const GLfloat invQ = solve_plane_recip(cx, cy, vPlane);
316               array->texcoords[0][count][0] = solve_plane(cx, cy, sPlane) * invQ;
317               array->texcoords[0][count][1] = solve_plane(cx, cy, tPlane) * invQ;
318               array->texcoords[0][count][2] = solve_plane(cx, cy, uPlane) * invQ;
319               array->lambda[0][count] = compute_lambda(sPlane, tPlane, vPlane,
320                                                      cx, cy, invQ,
321                                                      texWidth, texHeight);
322            }
323#elif defined(DO_MULTITEX)
324            {
325               GLuint unit;
326               for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
327                  if (ctx->Texture.Unit[unit]._ReallyEnabled) {
328                     GLfloat invQ = solve_plane_recip(cx, cy, vPlane[unit]);
329                     array->texcoords[unit][count][0] = solve_plane(cx, cy, sPlane[unit]) * invQ;
330                     array->texcoords[unit][count][1] = solve_plane(cx, cy, tPlane[unit]) * invQ;
331                     array->texcoords[unit][count][2] = solve_plane(cx, cy, uPlane[unit]) * invQ;
332                     array->lambda[unit][count] = compute_lambda(sPlane[unit],
333                                      tPlane[unit], vPlane[unit], cx, cy, invQ,
334                                      texWidth[unit], texHeight[unit]);
335                  }
336               }
337            }
338#endif
339            ix++;
340            count++;
341            coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
342         }
343
344         if (ix <= startX)
345            continue;
346
347         span.x = startX;
348         span.y = iy;
349         span.end = (GLuint) ix - (GLuint) startX;
350         ASSERT(span.interpMask == 0);
351#if defined(DO_MULTITEX) || defined(DO_TEX)
352         _mesa_write_texture_span(ctx, &span);
353#elif defined(DO_RGBA)
354         _mesa_write_rgba_span(ctx, &span);
355#elif defined(DO_INDEX)
356         _mesa_write_index_span(ctx, &span);
357#endif
358      }
359   }
360   else {
361      /* scan right to left */
362      const GLfloat *pMin = vMin->win;
363      const GLfloat *pMid = vMid->win;
364      const GLfloat *pMax = vMax->win;
365      const GLfloat dxdy = majDx / majDy;
366      const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
367      GLfloat x = pMin[0] - (yMin - iyMin) * dxdy;
368      GLint iy;
369      for (iy = iyMin; iy < iyMax; iy++, x += dxdy) {
370         GLint ix, left, startX = (GLint) (x + xAdj);
371         GLuint count, n;
372         GLfloat coverage = 0.0F;
373
374         /* make sure we're not past the window edge */
375         if (startX >= ctx->DrawBuffer->_Xmax) {
376            startX = ctx->DrawBuffer->_Xmax - 1;
377         }
378
379         /* skip fragments with zero coverage */
380         while (startX >= 0) {
381            coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
382            if (coverage > 0.0F)
383               break;
384            startX--;
385         }
386
387         /* enter interior of triangle */
388         ix = startX;
389         count = 0;
390         while (coverage > 0.0F) {
391            /* (cx,cy) = center of fragment */
392            const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
393            struct span_arrays *array = span.array;
394#ifdef DO_INDEX
395            array->coverage[ix] = (GLfloat) compute_coveragei(pMin, pMax, pMid, ix, iy);
396#else
397            array->coverage[ix] = coverage;
398#endif
399#ifdef DO_Z
400            array->z[ix] = (GLdepth) solve_plane(cx, cy, zPlane);
401#endif
402#ifdef DO_FOG
403            array->fog[ix] = solve_plane(cx, cy, fogPlane);
404#endif
405#ifdef DO_RGBA
406            array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane);
407            array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane);
408            array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane);
409            array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane);
410#endif
411#ifdef DO_INDEX
412            array->index[ix] = (GLint) solve_plane(cx, cy, iPlane);
413#endif
414#ifdef DO_SPEC
415            array->spec[ix][RCOMP] = solve_plane_chan(cx, cy, srPlane);
416            array->spec[ix][GCOMP] = solve_plane_chan(cx, cy, sgPlane);
417            array->spec[ix][BCOMP] = solve_plane_chan(cx, cy, sbPlane);
418#endif
419#ifdef DO_TEX
420            {
421               const GLfloat invQ = solve_plane_recip(cx, cy, vPlane);
422               array->texcoords[0][ix][0] = solve_plane(cx, cy, sPlane) * invQ;
423               array->texcoords[0][ix][1] = solve_plane(cx, cy, tPlane) * invQ;
424               array->texcoords[0][ix][2] = solve_plane(cx, cy, uPlane) * invQ;
425               array->lambda[0][ix] = compute_lambda(sPlane, tPlane, vPlane,
426                                          cx, cy, invQ, texWidth, texHeight);
427            }
428#elif defined(DO_MULTITEX)
429            {
430               GLuint unit;
431               for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
432                  if (ctx->Texture.Unit[unit]._ReallyEnabled) {
433                     GLfloat invQ = solve_plane_recip(cx, cy, vPlane[unit]);
434                     array->texcoords[unit][ix][0] = solve_plane(cx, cy, sPlane[unit]) * invQ;
435                     array->texcoords[unit][ix][1] = solve_plane(cx, cy, tPlane[unit]) * invQ;
436                     array->texcoords[unit][ix][2] = solve_plane(cx, cy, uPlane[unit]) * invQ;
437                     array->lambda[unit][ix] = compute_lambda(sPlane[unit],
438                                                            tPlane[unit],
439                                                            vPlane[unit],
440                                                            cx, cy, invQ,
441                                                            texWidth[unit],
442                                                            texHeight[unit]);
443                  }
444               }
445            }
446#endif
447            ix--;
448            count++;
449            coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
450         }
451
452         if (startX <= ix)
453            continue;
454
455         n = (GLuint) startX - (GLuint) ix;
456
457         left = ix + 1;
458
459         /* shift all values to the left */
460         /* XXX this is temporary */
461         {
462            struct span_arrays *array = span.array;
463            GLint j;
464            for (j = 0; j < (GLint) n; j++) {
465#ifdef DO_RGBA
466               COPY_4V(array->rgba[j], array->rgba[j + left]);
467#endif
468#ifdef DO_SPEC
469               COPY_4V(array->spec[j], array->spec[j + left]);
470#endif
471#ifdef DO_INDEX
472               array->index[j] = array->index[j + left];
473#endif
474#ifdef DO_Z
475               array->z[j] = array->z[j + left];
476#endif
477#ifdef DO_FOG
478               array->fog[j] = array->fog[j + left];
479#endif
480#ifdef DO_TEX
481               COPY_4V(array->texcoords[0][j], array->texcoords[0][j + left]);
482#endif
483#if defined(DO_MULTITEX) || defined(DO_TEX)
484               array->lambda[0][j] = array->lambda[0][j + left];
485#endif
486               array->coverage[j] = array->coverage[j + left];
487            }
488         }
489#ifdef DO_MULTITEX
490         /* shift texcoords */
491         {
492            struct span_arrays *array = span.array;
493            GLuint unit;
494            for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
495               if (ctx->Texture.Unit[unit]._ReallyEnabled) {
496                  GLint j;
497                  for (j = 0; j < (GLint) n; j++) {
498		     array->texcoords[unit][j][0] = array->texcoords[unit][j + left][0];
499                     array->texcoords[unit][j][1] = array->texcoords[unit][j + left][1];
500                     array->texcoords[unit][j][2] = array->texcoords[unit][j + left][2];
501                     array->lambda[unit][j] = array->lambda[unit][j + left];
502                  }
503               }
504            }
505         }
506#endif
507
508         span.x = left;
509         span.y = iy;
510         span.end = n;
511         ASSERT(span.interpMask == 0);
512#if defined(DO_MULTITEX) || defined(DO_TEX)
513         _mesa_write_texture_span(ctx, &span);
514#elif defined(DO_RGBA)
515         _mesa_write_rgba_span(ctx, &span);
516#elif defined(DO_INDEX)
517         _mesa_write_index_span(ctx, &span);
518#endif
519      }
520   }
521}
522
523
524#ifdef DO_Z
525#undef DO_Z
526#endif
527
528#ifdef DO_FOG
529#undef DO_FOG
530#endif
531
532#ifdef DO_RGBA
533#undef DO_RGBA
534#endif
535
536#ifdef DO_INDEX
537#undef DO_INDEX
538#endif
539
540#ifdef DO_SPEC
541#undef DO_SPEC
542#endif
543
544#ifdef DO_TEX
545#undef DO_TEX
546#endif
547
548#ifdef DO_MULTITEX
549#undef DO_MULTITEX
550#endif
551
552#ifdef DO_OCCLUSION_TEST
553#undef DO_OCCLUSION_TEST
554#endif
555