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