s_aatritemp.h revision bf80e1ed620836e2ca0dd3f7d2d4cb187d17563d
1/* $Id: s_aatritemp.h,v 1.29 2002/04/19 14:05:50 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 = SWRAST_CONTEXT(ctx)->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#ifdef DO_INDEX 288 span->coverage[count] = (GLfloat) compute_coveragei(pMin, pMid, pMax, ix, iy); 289#else 290 span->coverage[count] = coverage; 291#endif 292#ifdef DO_Z 293 span->zArray[count] = (GLdepth) solve_plane(cx, cy, zPlane); 294#endif 295#ifdef DO_FOG 296 span->fogArray[count] = solve_plane(cx, cy, fogPlane); 297#endif 298#ifdef DO_RGBA 299 span->color.rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane); 300 span->color.rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane); 301 span->color.rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane); 302 span->color.rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane); 303#endif 304#ifdef DO_INDEX 305 span->color.index[count] = (GLint) solve_plane(cx, cy, iPlane); 306#endif 307#ifdef DO_SPEC 308 span->specArray[count][RCOMP] = solve_plane_chan(cx, cy, srPlane); 309 span->specArray[count][GCOMP] = solve_plane_chan(cx, cy, sgPlane); 310 span->specArray[count][BCOMP] = solve_plane_chan(cx, cy, sbPlane); 311#endif 312#ifdef DO_TEX 313 { 314 const GLfloat invQ = solve_plane_recip(cx, cy, vPlane); 315 span->texcoords[0][count][0] = solve_plane(cx, cy, sPlane) * invQ; 316 span->texcoords[0][count][1] = solve_plane(cx, cy, tPlane) * invQ; 317 span->texcoords[0][count][2] = solve_plane(cx, cy, uPlane) * invQ; 318 span->lambda[0][count] = compute_lambda(sPlane, tPlane, vPlane, 319 cx, cy, invQ, 320 texWidth, texHeight); 321 } 322#elif defined(DO_MULTITEX) 323 { 324 GLuint unit; 325 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 326 if (ctx->Texture.Unit[unit]._ReallyEnabled) { 327 GLfloat invQ = solve_plane_recip(cx, cy, vPlane[unit]); 328 span->texcoords[unit][count][0] = solve_plane(cx, cy, sPlane[unit]) * invQ; 329 span->texcoords[unit][count][1] = solve_plane(cx, cy, tPlane[unit]) * invQ; 330 span->texcoords[unit][count][2] = solve_plane(cx, cy, uPlane[unit]) * invQ; 331 span->lambda[unit][count] = compute_lambda(sPlane[unit], 332 tPlane[unit], vPlane[unit], cx, cy, invQ, 333 texWidth[unit], texHeight[unit]); 334 } 335 } 336 } 337#endif 338 ix++; 339 count++; 340 coverage = compute_coveragef(pMin, pMid, pMax, ix, iy); 341 } 342 343 if (ix <= startX) 344 continue; 345 346 span->x = startX; 347 span->y = iy; 348 span->end = (GLuint) ix - (GLuint) startX; 349 ASSERT(span->interpMask == 0); 350#if defined(DO_MULTITEX) || defined(DO_TEX) 351 _mesa_write_texture_span(ctx, span); 352#elif defined(DO_RGBA) 353 _mesa_write_rgba_span(ctx, span); 354#elif defined(DO_INDEX) 355 _mesa_write_index_span(ctx, span); 356#endif 357 } 358 } 359 else { 360 /* scan right to left */ 361 const GLfloat *pMin = vMin->win; 362 const GLfloat *pMid = vMid->win; 363 const GLfloat *pMax = vMax->win; 364 const GLfloat dxdy = majDx / majDy; 365 const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F; 366 GLfloat x = pMin[0] - (yMin - iyMin) * dxdy; 367 GLint iy; 368 for (iy = iyMin; iy < iyMax; iy++, x += dxdy) { 369 GLint ix, left, startX = (GLint) (x + xAdj); 370 GLuint count, n; 371 GLfloat coverage = 0.0F; 372 373 /* make sure we're not past the window edge */ 374 if (startX >= ctx->DrawBuffer->_Xmax) { 375 startX = ctx->DrawBuffer->_Xmax - 1; 376 } 377 378 /* skip fragments with zero coverage */ 379 while (startX >= 0) { 380 coverage = compute_coveragef(pMin, pMax, pMid, startX, iy); 381 if (coverage > 0.0F) 382 break; 383 startX--; 384 } 385 386 /* enter interior of triangle */ 387 ix = startX; 388 count = 0; 389 while (coverage > 0.0F) { 390 /* (cx,cy) = center of fragment */ 391 const GLfloat cx = ix + 0.5F, cy = iy + 0.5F; 392#ifdef DO_INDEX 393 span->coverage[ix] = (GLfloat) compute_coveragei(pMin, pMax, pMid, ix, iy); 394#else 395 span->coverage[ix] = coverage; 396#endif 397#ifdef DO_Z 398 span->zArray[ix] = (GLdepth) solve_plane(cx, cy, zPlane); 399#endif 400#ifdef DO_FOG 401 span->fogArray[ix] = solve_plane(cx, cy, fogPlane); 402#endif 403#ifdef DO_RGBA 404 span->color.rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane); 405 span->color.rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane); 406 span->color.rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane); 407 span->color.rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane); 408#endif 409#ifdef DO_INDEX 410 span->color.index[ix] = (GLint) solve_plane(cx, cy, iPlane); 411#endif 412#ifdef DO_SPEC 413 span->specArray[ix][RCOMP] = solve_plane_chan(cx, cy, srPlane); 414 span->specArray[ix][GCOMP] = solve_plane_chan(cx, cy, sgPlane); 415 span->specArray[ix][BCOMP] = solve_plane_chan(cx, cy, sbPlane); 416#endif 417#ifdef DO_TEX 418 { 419 const GLfloat invQ = solve_plane_recip(cx, cy, vPlane); 420 span->texcoords[0][ix][0] = solve_plane(cx, cy, sPlane) * invQ; 421 span->texcoords[0][ix][1] = solve_plane(cx, cy, tPlane) * invQ; 422 span->texcoords[0][ix][2] = solve_plane(cx, cy, uPlane) * invQ; 423 span->lambda[0][ix] = compute_lambda(sPlane, tPlane, vPlane, 424 cx, cy, invQ, texWidth, texHeight); 425 } 426#elif defined(DO_MULTITEX) 427 { 428 GLuint unit; 429 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 430 if (ctx->Texture.Unit[unit]._ReallyEnabled) { 431 GLfloat invQ = solve_plane_recip(cx, cy, vPlane[unit]); 432 span->texcoords[unit][ix][0] = solve_plane(cx, cy, sPlane[unit]) * invQ; 433 span->texcoords[unit][ix][1] = solve_plane(cx, cy, tPlane[unit]) * invQ; 434 span->texcoords[unit][ix][2] = solve_plane(cx, cy, uPlane[unit]) * invQ; 435 span->lambda[unit][ix] = compute_lambda(sPlane[unit], 436 tPlane[unit], 437 vPlane[unit], 438 cx, cy, invQ, 439 texWidth[unit], 440 texHeight[unit]); 441 } 442 } 443 } 444#endif 445 ix--; 446 count++; 447 coverage = compute_coveragef(pMin, pMax, pMid, ix, iy); 448 } 449 450 if (startX <= ix) 451 continue; 452 453 n = (GLuint) startX - (GLuint) ix; 454 455 left = ix + 1; 456 457 /* shift all values to the left */ 458 /* XXX this is temporary */ 459 { 460 GLint j; 461 for (j = 0; j < (GLint) n; j++) { 462#ifdef DO_RGBA 463 COPY_4V(span->color.rgba[j], span->color.rgba[j + left]); 464#endif 465#ifdef DO_SPEC 466 COPY_4V(span->specArray[j], span->specArray[j + left]); 467#endif 468#ifdef DO_INDEX 469 span->color.index[j] = span->color.index[j + left]; 470#endif 471#ifdef DO_Z 472 span->zArray[j] = span->zArray[j + left]; 473#endif 474#ifdef DO_FOG 475 span->fogArray[j] = span->fogArray[j + left]; 476#endif 477#ifdef DO_TEX 478 COPY_4V(span->texcoords[0][j], span->texcoords[0][j + left]); 479#endif 480#if defined(DO_MULTITEX) || defined(DO_TEX) 481 span->lambda[0][j] = span->lambda[0][j + left]; 482#endif 483 span->coverage[j] = span->coverage[j + left]; 484 } 485 } 486#ifdef DO_MULTITEX 487 /* shift texcoords */ 488 { 489 GLuint unit; 490 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 491 if (ctx->Texture.Unit[unit]._ReallyEnabled) { 492 GLint j; 493 for (j = 0; j < (GLint) n; j++) { 494 span->texcoords[unit][j][0] = span->texcoords[unit][j + left][0]; 495 span->texcoords[unit][j][1] = span->texcoords[unit][j + left][1]; 496 span->texcoords[unit][j][2] = span->texcoords[unit][j + left][2]; 497 span->lambda[unit][j] = span->lambda[unit][j + left]; 498 } 499 } 500 } 501 } 502#endif 503 504 span->x = left; 505 span->y = iy; 506 span->end = n; 507 ASSERT(span->interpMask == 0); 508#if defined(DO_MULTITEX) || defined(DO_TEX) 509 _mesa_write_texture_span(ctx, span); 510#elif defined(DO_RGBA) 511 _mesa_write_rgba_span(ctx, span); 512#elif defined(DO_INDEX) 513 _mesa_write_index_span(ctx, span); 514#endif 515 } 516 } 517} 518 519 520#ifdef DO_Z 521#undef DO_Z 522#endif 523 524#ifdef DO_FOG 525#undef DO_FOG 526#endif 527 528#ifdef DO_RGBA 529#undef DO_RGBA 530#endif 531 532#ifdef DO_INDEX 533#undef DO_INDEX 534#endif 535 536#ifdef DO_SPEC 537#undef DO_SPEC 538#endif 539 540#ifdef DO_TEX 541#undef DO_TEX 542#endif 543 544#ifdef DO_MULTITEX 545#undef DO_MULTITEX 546#endif 547 548#ifdef DO_OCCLUSION_TEST 549#undef DO_OCCLUSION_TEST 550#endif 551