s_triangle.c revision 5d6ecf25f89b152638f68ba683611f73c51b52a4
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.3 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 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. 23 */ 24 25 26/* 27 * When the device driver doesn't implement triangle rasterization it 28 * can hook in _swrast_Triangle, which eventually calls one of these 29 * functions to draw triangles. 30 */ 31 32#include "glheader.h" 33#include "context.h" 34#include "colormac.h" 35#include "imports.h" 36#include "macros.h" 37#include "texformat.h" 38 39#include "s_aatriangle.h" 40#include "s_context.h" 41#include "s_depth.h" 42#include "s_feedback.h" 43#include "s_span.h" 44#include "s_triangle.h" 45 46 47/* 48 * Just used for feedback mode. 49 */ 50GLboolean 51_swrast_culltriangle( GLcontext *ctx, 52 const SWvertex *v0, 53 const SWvertex *v1, 54 const SWvertex *v2 ) 55{ 56 GLfloat ex = v1->win[0] - v0->win[0]; 57 GLfloat ey = v1->win[1] - v0->win[1]; 58 GLfloat fx = v2->win[0] - v0->win[0]; 59 GLfloat fy = v2->win[1] - v0->win[1]; 60 GLfloat c = ex*fy-ey*fx; 61 62 if (c * SWRAST_CONTEXT(ctx)->_BackfaceSign > 0) 63 return 0; 64 65 return 1; 66} 67 68 69 70/* 71 * Render a flat-shaded color index triangle. 72 */ 73#define NAME flat_ci_triangle 74#define INTERP_Z 1 75#define INTERP_FOG 1 76#define SETUP_CODE \ 77 span.interpMask |= SPAN_INDEX; \ 78 span.index = FloatToFixed(v2->index);\ 79 span.indexStep = 0; 80#define RENDER_SPAN( span ) _swrast_write_index_span(ctx, &span); 81#include "s_tritemp.h" 82 83 84 85/* 86 * Render a smooth-shaded color index triangle. 87 */ 88#define NAME smooth_ci_triangle 89#define INTERP_Z 1 90#define INTERP_FOG 1 91#define INTERP_INDEX 1 92#define RENDER_SPAN( span ) _swrast_write_index_span(ctx, &span); 93#include "s_tritemp.h" 94 95 96 97/* 98 * Render a flat-shaded RGBA triangle. 99 */ 100#define NAME flat_rgba_triangle 101#define INTERP_Z 1 102#define INTERP_FOG 1 103#define SETUP_CODE \ 104 ASSERT(ctx->Texture._EnabledCoordUnits == 0);\ 105 ASSERT(ctx->Light.ShadeModel==GL_FLAT); \ 106 span.interpMask |= SPAN_RGBA; \ 107 span.red = ChanToFixed(v2->color[0]); \ 108 span.green = ChanToFixed(v2->color[1]); \ 109 span.blue = ChanToFixed(v2->color[2]); \ 110 span.alpha = ChanToFixed(v2->color[3]); \ 111 span.redStep = 0; \ 112 span.greenStep = 0; \ 113 span.blueStep = 0; \ 114 span.alphaStep = 0; 115#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 116#include "s_tritemp.h" 117 118 119 120/* 121 * Render a smooth-shaded RGBA triangle. 122 */ 123#define NAME smooth_rgba_triangle 124#define INTERP_Z 1 125#define INTERP_FOG 1 126#define INTERP_RGB 1 127#define INTERP_ALPHA 1 128#define SETUP_CODE \ 129 { \ 130 /* texturing must be off */ \ 131 ASSERT(ctx->Texture._EnabledCoordUnits == 0); \ 132 ASSERT(ctx->Light.ShadeModel==GL_SMOOTH); \ 133 } 134#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 135#include "s_tritemp.h" 136 137 138 139/* 140 * Render an RGB, GL_DECAL, textured triangle. 141 * Interpolate S,T only w/out mipmapping or perspective correction. 142 * 143 * No fog. 144 */ 145#define NAME simple_textured_triangle 146#define INTERP_INT_TEX 1 147#define S_SCALE twidth 148#define T_SCALE theight 149 150#define SETUP_CODE \ 151 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];\ 152 struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D; \ 153 const GLint b = obj->BaseLevel; \ 154 const GLfloat twidth = (GLfloat) obj->Image[0][b]->Width; \ 155 const GLfloat theight = (GLfloat) obj->Image[0][b]->Height; \ 156 const GLint twidth_log2 = obj->Image[0][b]->WidthLog2; \ 157 const GLchan *texture = (const GLchan *) obj->Image[0][b]->Data; \ 158 const GLint smask = obj->Image[0][b]->Width - 1; \ 159 const GLint tmask = obj->Image[0][b]->Height - 1; \ 160 if (!texture) { \ 161 /* this shouldn't happen */ \ 162 return; \ 163 } 164 165#define RENDER_SPAN( span ) \ 166 GLuint i; \ 167 span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ 168 span.intTex[1] -= FIXED_HALF; \ 169 for (i = 0; i < span.end; i++) { \ 170 GLint s = FixedToInt(span.intTex[0]) & smask; \ 171 GLint t = FixedToInt(span.intTex[1]) & tmask; \ 172 GLint pos = (t << twidth_log2) + s; \ 173 pos = pos + pos + pos; /* multiply by 3 */ \ 174 span.array->rgb[i][RCOMP] = texture[pos]; \ 175 span.array->rgb[i][GCOMP] = texture[pos+1]; \ 176 span.array->rgb[i][BCOMP] = texture[pos+2]; \ 177 span.intTex[0] += span.intTexStep[0]; \ 178 span.intTex[1] += span.intTexStep[1]; \ 179 } \ 180 rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, span.array->rgb, NULL); 181 182#include "s_tritemp.h" 183 184 185 186/* 187 * Render an RGB, GL_DECAL, textured triangle. 188 * Interpolate S,T, GL_LESS depth test, w/out mipmapping or 189 * perspective correction. 190 * Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE) 191 * 192 * No fog. 193 */ 194#define NAME simple_z_textured_triangle 195#define INTERP_Z 1 196#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE 197#define INTERP_INT_TEX 1 198#define S_SCALE twidth 199#define T_SCALE theight 200 201#define SETUP_CODE \ 202 struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];\ 203 struct gl_texture_object *obj = ctx->Texture.Unit[0].Current2D; \ 204 const GLint b = obj->BaseLevel; \ 205 const GLfloat twidth = (GLfloat) obj->Image[0][b]->Width; \ 206 const GLfloat theight = (GLfloat) obj->Image[0][b]->Height; \ 207 const GLint twidth_log2 = obj->Image[0][b]->WidthLog2; \ 208 const GLchan *texture = (const GLchan *) obj->Image[0][b]->Data; \ 209 const GLint smask = obj->Image[0][b]->Width - 1; \ 210 const GLint tmask = obj->Image[0][b]->Height - 1; \ 211 if (!texture) { \ 212 /* this shouldn't happen */ \ 213 return; \ 214 } 215 216#define RENDER_SPAN( span ) \ 217 GLuint i; \ 218 span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \ 219 span.intTex[1] -= FIXED_HALF; \ 220 for (i = 0; i < span.end; i++) { \ 221 const GLdepth z = FixedToDepth(span.z); \ 222 if (z < zRow[i]) { \ 223 GLint s = FixedToInt(span.intTex[0]) & smask; \ 224 GLint t = FixedToInt(span.intTex[1]) & tmask; \ 225 GLint pos = (t << twidth_log2) + s; \ 226 pos = pos + pos + pos; /* multiply by 3 */ \ 227 span.array->rgb[i][RCOMP] = texture[pos]; \ 228 span.array->rgb[i][GCOMP] = texture[pos+1]; \ 229 span.array->rgb[i][BCOMP] = texture[pos+2]; \ 230 zRow[i] = z; \ 231 span.array->mask[i] = 1; \ 232 } \ 233 else { \ 234 span.array->mask[i] = 0; \ 235 } \ 236 span.intTex[0] += span.intTexStep[0]; \ 237 span.intTex[1] += span.intTexStep[1]; \ 238 span.z += span.zStep; \ 239 } \ 240 rb->PutRowRGB(ctx, rb, span.end, span.x, span.y, \ 241 span.array->rgb, span.array->mask); 242 243#include "s_tritemp.h" 244 245 246 247#if CHAN_TYPE != GL_FLOAT 248 249struct affine_info 250{ 251 GLenum filter; 252 GLenum format; 253 GLenum envmode; 254 GLint smask, tmask; 255 GLint twidth_log2; 256 const GLchan *texture; 257 GLfixed er, eg, eb, ea; 258 GLint tbytesline, tsize; 259}; 260 261 262/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA 263 * textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD 264 * texture env modes. 265 */ 266static INLINE void 267affine_span(GLcontext *ctx, struct sw_span *span, 268 struct affine_info *info) 269{ 270 GLchan sample[4]; /* the filtered texture sample */ 271 272 /* Instead of defining a function for each mode, a test is done 273 * between the outer and inner loops. This is to reduce code size 274 * and complexity. Observe that an optimizing compiler kills 275 * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). 276 */ 277 278#define NEAREST_RGB \ 279 sample[RCOMP] = tex00[RCOMP]; \ 280 sample[GCOMP] = tex00[GCOMP]; \ 281 sample[BCOMP] = tex00[BCOMP]; \ 282 sample[ACOMP] = CHAN_MAX 283 284#define LINEAR_RGB \ 285 sample[RCOMP] = (ti * (si * tex00[0] + sf * tex01[0]) + \ 286 tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT; \ 287 sample[GCOMP] = (ti * (si * tex00[1] + sf * tex01[1]) + \ 288 tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT; \ 289 sample[BCOMP] = (ti * (si * tex00[2] + sf * tex01[2]) + \ 290 tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT; \ 291 sample[ACOMP] = CHAN_MAX 292 293#define NEAREST_RGBA COPY_CHAN4(sample, tex00) 294 295#define LINEAR_RGBA \ 296 sample[RCOMP] = (ti * (si * tex00[0] + sf * tex01[0]) + \ 297 tf * (si * tex10[0] + sf * tex11[0])) >> 2 * FIXED_SHIFT;\ 298 sample[GCOMP] = (ti * (si * tex00[1] + sf * tex01[1]) + \ 299 tf * (si * tex10[1] + sf * tex11[1])) >> 2 * FIXED_SHIFT;\ 300 sample[BCOMP] = (ti * (si * tex00[2] + sf * tex01[2]) + \ 301 tf * (si * tex10[2] + sf * tex11[2])) >> 2 * FIXED_SHIFT;\ 302 sample[ACOMP] = (ti * (si * tex00[3] + sf * tex01[3]) + \ 303 tf * (si * tex10[3] + sf * tex11[3])) >> 2 * FIXED_SHIFT 304 305#define MODULATE \ 306 dest[RCOMP] = span->red * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 307 dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 308 dest[BCOMP] = span->blue * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \ 309 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8) 310 311#define DECAL \ 312 dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red + \ 313 ((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT)) \ 314 >> (FIXED_SHIFT + 8); \ 315 dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green + \ 316 ((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT)) \ 317 >> (FIXED_SHIFT + 8); \ 318 dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue + \ 319 ((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT)) \ 320 >> (FIXED_SHIFT + 8); \ 321 dest[ACOMP] = FixedToInt(span->alpha) 322 323#define BLEND \ 324 dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red \ 325 + (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8); \ 326 dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green \ 327 + (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8); \ 328 dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue \ 329 + (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8); \ 330 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8) 331 332#define REPLACE COPY_CHAN4(dest, sample) 333 334#define ADD \ 335 { \ 336 GLint rSum = FixedToInt(span->red) + (GLint) sample[RCOMP]; \ 337 GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP]; \ 338 GLint bSum = FixedToInt(span->blue) + (GLint) sample[BCOMP]; \ 339 dest[RCOMP] = MIN2(rSum, CHAN_MAX); \ 340 dest[GCOMP] = MIN2(gSum, CHAN_MAX); \ 341 dest[BCOMP] = MIN2(bSum, CHAN_MAX); \ 342 dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \ 343 } 344 345/* shortcuts */ 346 347#define NEAREST_RGB_REPLACE \ 348 NEAREST_RGB; \ 349 dest[0] = sample[0]; \ 350 dest[1] = sample[1]; \ 351 dest[2] = sample[2]; \ 352 dest[3] = FixedToInt(span->alpha); 353 354#define NEAREST_RGBA_REPLACE COPY_CHAN4(dest, tex00) 355 356#define SPAN_NEAREST(DO_TEX,COMP) \ 357 for (i = 0; i < span->end; i++) { \ 358 /* Isn't it necessary to use FixedFloor below?? */ \ 359 GLint s = FixedToInt(span->intTex[0]) & info->smask; \ 360 GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ 361 GLint pos = (t << info->twidth_log2) + s; \ 362 const GLchan *tex00 = info->texture + COMP * pos; \ 363 DO_TEX; \ 364 span->red += span->redStep; \ 365 span->green += span->greenStep; \ 366 span->blue += span->blueStep; \ 367 span->alpha += span->alphaStep; \ 368 span->intTex[0] += span->intTexStep[0]; \ 369 span->intTex[1] += span->intTexStep[1]; \ 370 dest += 4; \ 371 } 372 373#define SPAN_LINEAR(DO_TEX,COMP) \ 374 for (i = 0; i < span->end; i++) { \ 375 /* Isn't it necessary to use FixedFloor below?? */ \ 376 GLint s = FixedToInt(span->intTex[0]) & info->smask; \ 377 GLint t = FixedToInt(span->intTex[1]) & info->tmask; \ 378 GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK; \ 379 GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK; \ 380 GLfixed si = FIXED_FRAC_MASK - sf; \ 381 GLfixed ti = FIXED_FRAC_MASK - tf; \ 382 GLint pos = (t << info->twidth_log2) + s; \ 383 const GLchan *tex00 = info->texture + COMP * pos; \ 384 const GLchan *tex10 = tex00 + info->tbytesline; \ 385 const GLchan *tex01 = tex00 + COMP; \ 386 const GLchan *tex11 = tex10 + COMP; \ 387 (void) ti; \ 388 (void) si; \ 389 if (t == info->tmask) { \ 390 tex10 -= info->tsize; \ 391 tex11 -= info->tsize; \ 392 } \ 393 if (s == info->smask) { \ 394 tex01 -= info->tbytesline; \ 395 tex11 -= info->tbytesline; \ 396 } \ 397 DO_TEX; \ 398 span->red += span->redStep; \ 399 span->green += span->greenStep; \ 400 span->blue += span->blueStep; \ 401 span->alpha += span->alphaStep; \ 402 span->intTex[0] += span->intTexStep[0]; \ 403 span->intTex[1] += span->intTexStep[1]; \ 404 dest += 4; \ 405 } 406 407 408 GLuint i; 409 GLchan *dest = span->array->rgba[0]; 410 411 span->intTex[0] -= FIXED_HALF; 412 span->intTex[1] -= FIXED_HALF; 413 switch (info->filter) { 414 case GL_NEAREST: 415 switch (info->format) { 416 case GL_RGB: 417 switch (info->envmode) { 418 case GL_MODULATE: 419 SPAN_NEAREST(NEAREST_RGB;MODULATE,3); 420 break; 421 case GL_DECAL: 422 case GL_REPLACE: 423 SPAN_NEAREST(NEAREST_RGB_REPLACE,3); 424 break; 425 case GL_BLEND: 426 SPAN_NEAREST(NEAREST_RGB;BLEND,3); 427 break; 428 case GL_ADD: 429 SPAN_NEAREST(NEAREST_RGB;ADD,3); 430 break; 431 default: 432 _mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR"); 433 return; 434 } 435 break; 436 case GL_RGBA: 437 switch(info->envmode) { 438 case GL_MODULATE: 439 SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); 440 break; 441 case GL_DECAL: 442 SPAN_NEAREST(NEAREST_RGBA;DECAL,4); 443 break; 444 case GL_BLEND: 445 SPAN_NEAREST(NEAREST_RGBA;BLEND,4); 446 break; 447 case GL_ADD: 448 SPAN_NEAREST(NEAREST_RGBA;ADD,4); 449 break; 450 case GL_REPLACE: 451 SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); 452 break; 453 default: 454 _mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR"); 455 return; 456 } 457 break; 458 } 459 break; 460 461 case GL_LINEAR: 462 span->intTex[0] -= FIXED_HALF; 463 span->intTex[1] -= FIXED_HALF; 464 switch (info->format) { 465 case GL_RGB: 466 switch (info->envmode) { 467 case GL_MODULATE: 468 SPAN_LINEAR(LINEAR_RGB;MODULATE,3); 469 break; 470 case GL_DECAL: 471 case GL_REPLACE: 472 SPAN_LINEAR(LINEAR_RGB;REPLACE,3); 473 break; 474 case GL_BLEND: 475 SPAN_LINEAR(LINEAR_RGB;BLEND,3); 476 break; 477 case GL_ADD: 478 SPAN_LINEAR(LINEAR_RGB;ADD,3); 479 break; 480 default: 481 _mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR"); 482 return; 483 } 484 break; 485 case GL_RGBA: 486 switch (info->envmode) { 487 case GL_MODULATE: 488 SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); 489 break; 490 case GL_DECAL: 491 SPAN_LINEAR(LINEAR_RGBA;DECAL,4); 492 break; 493 case GL_BLEND: 494 SPAN_LINEAR(LINEAR_RGBA;BLEND,4); 495 break; 496 case GL_ADD: 497 SPAN_LINEAR(LINEAR_RGBA;ADD,4); 498 break; 499 case GL_REPLACE: 500 SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); 501 break; 502 default: 503 _mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR"); 504 return; 505 } 506 break; 507 } 508 break; 509 } 510 span->interpMask &= ~SPAN_RGBA; 511 ASSERT(span->arrayMask & SPAN_RGBA); 512 _swrast_write_rgba_span(ctx, span); 513 514#undef SPAN_NEAREST 515#undef SPAN_LINEAR 516} 517 518 519 520/* 521 * Render an RGB/RGBA textured triangle without perspective correction. 522 */ 523#define NAME affine_textured_triangle 524#define INTERP_Z 1 525#define INTERP_FOG 1 526#define INTERP_RGB 1 527#define INTERP_ALPHA 1 528#define INTERP_INT_TEX 1 529#define S_SCALE twidth 530#define T_SCALE theight 531 532#define SETUP_CODE \ 533 struct affine_info info; \ 534 struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ 535 struct gl_texture_object *obj = unit->Current2D; \ 536 const GLint b = obj->BaseLevel; \ 537 const GLfloat twidth = (GLfloat) obj->Image[0][b]->Width; \ 538 const GLfloat theight = (GLfloat) obj->Image[0][b]->Height; \ 539 info.texture = (const GLchan *) obj->Image[0][b]->Data; \ 540 info.twidth_log2 = obj->Image[0][b]->WidthLog2; \ 541 info.smask = obj->Image[0][b]->Width - 1; \ 542 info.tmask = obj->Image[0][b]->Height - 1; \ 543 info.format = obj->Image[0][b]->Format; \ 544 info.filter = obj->MinFilter; \ 545 info.envmode = unit->EnvMode; \ 546 span.arrayMask |= SPAN_RGBA; \ 547 \ 548 if (info.envmode == GL_BLEND) { \ 549 /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ 550 info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ 551 info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ 552 info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ 553 info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ 554 } \ 555 if (!info.texture) { \ 556 /* this shouldn't happen */ \ 557 return; \ 558 } \ 559 \ 560 switch (info.format) { \ 561 case GL_ALPHA: \ 562 case GL_LUMINANCE: \ 563 case GL_INTENSITY: \ 564 info.tbytesline = obj->Image[0][b]->Width; \ 565 break; \ 566 case GL_LUMINANCE_ALPHA: \ 567 info.tbytesline = obj->Image[0][b]->Width * 2; \ 568 break; \ 569 case GL_RGB: \ 570 info.tbytesline = obj->Image[0][b]->Width * 3; \ 571 break; \ 572 case GL_RGBA: \ 573 info.tbytesline = obj->Image[0][b]->Width * 4; \ 574 break; \ 575 default: \ 576 _mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\ 577 return; \ 578 } \ 579 info.tsize = obj->Image[0][b]->Height * info.tbytesline; 580 581#define RENDER_SPAN( span ) affine_span(ctx, &span, &info); 582 583#include "s_tritemp.h" 584 585 586 587struct persp_info 588{ 589 GLenum filter; 590 GLenum format; 591 GLenum envmode; 592 GLint smask, tmask; 593 GLint twidth_log2; 594 const GLchan *texture; 595 GLfixed er, eg, eb, ea; /* texture env color */ 596 GLint tbytesline, tsize; 597}; 598 599 600static INLINE void 601fast_persp_span(GLcontext *ctx, struct sw_span *span, 602 struct persp_info *info) 603{ 604 GLchan sample[4]; /* the filtered texture sample */ 605 606 /* Instead of defining a function for each mode, a test is done 607 * between the outer and inner loops. This is to reduce code size 608 * and complexity. Observe that an optimizing compiler kills 609 * unused variables (for instance tf,sf,ti,si in case of GL_NEAREST). 610 */ 611#define SPAN_NEAREST(DO_TEX,COMP) \ 612 for (i = 0; i < span->end; i++) { \ 613 GLdouble invQ = tex_coord[2] ? \ 614 (1.0 / tex_coord[2]) : 1.0; \ 615 GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ 616 GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ 617 GLint s = IFLOOR(s_tmp) & info->smask; \ 618 GLint t = IFLOOR(t_tmp) & info->tmask; \ 619 GLint pos = (t << info->twidth_log2) + s; \ 620 const GLchan *tex00 = info->texture + COMP * pos; \ 621 DO_TEX; \ 622 span->red += span->redStep; \ 623 span->green += span->greenStep; \ 624 span->blue += span->blueStep; \ 625 span->alpha += span->alphaStep; \ 626 tex_coord[0] += tex_step[0]; \ 627 tex_coord[1] += tex_step[1]; \ 628 tex_coord[2] += tex_step[2]; \ 629 dest += 4; \ 630 } 631 632#define SPAN_LINEAR(DO_TEX,COMP) \ 633 for (i = 0; i < span->end; i++) { \ 634 GLdouble invQ = tex_coord[2] ? \ 635 (1.0 / tex_coord[2]) : 1.0; \ 636 GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \ 637 GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \ 638 GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF; \ 639 GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF; \ 640 GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask; \ 641 GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask; \ 642 GLfixed sf = s_fix & FIXED_FRAC_MASK; \ 643 GLfixed tf = t_fix & FIXED_FRAC_MASK; \ 644 GLfixed si = FIXED_FRAC_MASK - sf; \ 645 GLfixed ti = FIXED_FRAC_MASK - tf; \ 646 GLint pos = (t << info->twidth_log2) + s; \ 647 const GLchan *tex00 = info->texture + COMP * pos; \ 648 const GLchan *tex10 = tex00 + info->tbytesline; \ 649 const GLchan *tex01 = tex00 + COMP; \ 650 const GLchan *tex11 = tex10 + COMP; \ 651 (void) ti; \ 652 (void) si; \ 653 if (t == info->tmask) { \ 654 tex10 -= info->tsize; \ 655 tex11 -= info->tsize; \ 656 } \ 657 if (s == info->smask) { \ 658 tex01 -= info->tbytesline; \ 659 tex11 -= info->tbytesline; \ 660 } \ 661 DO_TEX; \ 662 span->red += span->redStep; \ 663 span->green += span->greenStep; \ 664 span->blue += span->blueStep; \ 665 span->alpha += span->alphaStep; \ 666 tex_coord[0] += tex_step[0]; \ 667 tex_coord[1] += tex_step[1]; \ 668 tex_coord[2] += tex_step[2]; \ 669 dest += 4; \ 670 } 671 672 GLuint i; 673 GLfloat tex_coord[3], tex_step[3]; 674 GLchan *dest = span->array->rgba[0]; 675 676 const GLuint savedTexEnable = ctx->Texture._EnabledUnits; 677 ctx->Texture._EnabledUnits = 0; 678 679 tex_coord[0] = span->tex[0][0] * (info->smask + 1); 680 tex_step[0] = span->texStepX[0][0] * (info->smask + 1); 681 tex_coord[1] = span->tex[0][1] * (info->tmask + 1); 682 tex_step[1] = span->texStepX[0][1] * (info->tmask + 1); 683 /* span->tex[0][2] only if 3D-texturing, here only 2D */ 684 tex_coord[2] = span->tex[0][3]; 685 tex_step[2] = span->texStepX[0][3]; 686 687 switch (info->filter) { 688 case GL_NEAREST: 689 switch (info->format) { 690 case GL_RGB: 691 switch (info->envmode) { 692 case GL_MODULATE: 693 SPAN_NEAREST(NEAREST_RGB;MODULATE,3); 694 break; 695 case GL_DECAL: 696 case GL_REPLACE: 697 SPAN_NEAREST(NEAREST_RGB_REPLACE,3); 698 break; 699 case GL_BLEND: 700 SPAN_NEAREST(NEAREST_RGB;BLEND,3); 701 break; 702 case GL_ADD: 703 SPAN_NEAREST(NEAREST_RGB;ADD,3); 704 break; 705 default: 706 _mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR"); 707 return; 708 } 709 break; 710 case GL_RGBA: 711 switch(info->envmode) { 712 case GL_MODULATE: 713 SPAN_NEAREST(NEAREST_RGBA;MODULATE,4); 714 break; 715 case GL_DECAL: 716 SPAN_NEAREST(NEAREST_RGBA;DECAL,4); 717 break; 718 case GL_BLEND: 719 SPAN_NEAREST(NEAREST_RGBA;BLEND,4); 720 break; 721 case GL_ADD: 722 SPAN_NEAREST(NEAREST_RGBA;ADD,4); 723 break; 724 case GL_REPLACE: 725 SPAN_NEAREST(NEAREST_RGBA_REPLACE,4); 726 break; 727 default: 728 _mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR"); 729 return; 730 } 731 break; 732 } 733 break; 734 735 case GL_LINEAR: 736 switch (info->format) { 737 case GL_RGB: 738 switch (info->envmode) { 739 case GL_MODULATE: 740 SPAN_LINEAR(LINEAR_RGB;MODULATE,3); 741 break; 742 case GL_DECAL: 743 case GL_REPLACE: 744 SPAN_LINEAR(LINEAR_RGB;REPLACE,3); 745 break; 746 case GL_BLEND: 747 SPAN_LINEAR(LINEAR_RGB;BLEND,3); 748 break; 749 case GL_ADD: 750 SPAN_LINEAR(LINEAR_RGB;ADD,3); 751 break; 752 default: 753 _mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR"); 754 return; 755 } 756 break; 757 case GL_RGBA: 758 switch (info->envmode) { 759 case GL_MODULATE: 760 SPAN_LINEAR(LINEAR_RGBA;MODULATE,4); 761 break; 762 case GL_DECAL: 763 SPAN_LINEAR(LINEAR_RGBA;DECAL,4); 764 break; 765 case GL_BLEND: 766 SPAN_LINEAR(LINEAR_RGBA;BLEND,4); 767 break; 768 case GL_ADD: 769 SPAN_LINEAR(LINEAR_RGBA;ADD,4); 770 break; 771 case GL_REPLACE: 772 SPAN_LINEAR(LINEAR_RGBA;REPLACE,4); 773 break; 774 default: 775 _mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR"); 776 return; 777 } 778 break; 779 } 780 break; 781 } 782 783 ASSERT(span->arrayMask & SPAN_RGBA); 784 _swrast_write_rgba_span(ctx, span); 785 786#undef SPAN_NEAREST 787#undef SPAN_LINEAR 788 789 /* restore state */ 790 ctx->Texture._EnabledUnits = savedTexEnable; 791} 792 793 794/* 795 * Render an perspective corrected RGB/RGBA textured triangle. 796 * The Q (aka V in Mesa) coordinate must be zero such that the divide 797 * by interpolated Q/W comes out right. 798 * 799 */ 800#define NAME persp_textured_triangle 801#define INTERP_Z 1 802#define INTERP_W 1 803#define INTERP_FOG 1 804#define INTERP_RGB 1 805#define INTERP_ALPHA 1 806#define INTERP_TEX 1 807 808#define SETUP_CODE \ 809 struct persp_info info; \ 810 const struct gl_texture_unit *unit = ctx->Texture.Unit+0; \ 811 const struct gl_texture_object *obj = unit->Current2D; \ 812 const GLint b = obj->BaseLevel; \ 813 info.texture = (const GLchan *) obj->Image[0][b]->Data; \ 814 info.twidth_log2 = obj->Image[0][b]->WidthLog2; \ 815 info.smask = obj->Image[0][b]->Width - 1; \ 816 info.tmask = obj->Image[0][b]->Height - 1; \ 817 info.format = obj->Image[0][b]->Format; \ 818 info.filter = obj->MinFilter; \ 819 info.envmode = unit->EnvMode; \ 820 \ 821 if (info.envmode == GL_BLEND) { \ 822 /* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \ 823 info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \ 824 info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \ 825 info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \ 826 info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \ 827 } \ 828 if (!info.texture) { \ 829 /* this shouldn't happen */ \ 830 return; \ 831 } \ 832 \ 833 switch (info.format) { \ 834 case GL_ALPHA: \ 835 case GL_LUMINANCE: \ 836 case GL_INTENSITY: \ 837 info.tbytesline = obj->Image[0][b]->Width; \ 838 break; \ 839 case GL_LUMINANCE_ALPHA: \ 840 info.tbytesline = obj->Image[0][b]->Width * 2; \ 841 break; \ 842 case GL_RGB: \ 843 info.tbytesline = obj->Image[0][b]->Width * 3; \ 844 break; \ 845 case GL_RGBA: \ 846 info.tbytesline = obj->Image[0][b]->Width * 4; \ 847 break; \ 848 default: \ 849 _mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\ 850 return; \ 851 } \ 852 info.tsize = obj->Image[0][b]->Height * info.tbytesline; 853 854#define RENDER_SPAN( span ) \ 855 span.interpMask &= ~SPAN_RGBA; \ 856 span.arrayMask |= SPAN_RGBA; \ 857 fast_persp_span(ctx, &span, &info); 858 859#include "s_tritemp.h" 860 861 862#endif /* CHAN_BITS != GL_FLOAT */ 863 864 865 866 867/* 868 * Render a smooth-shaded, textured, RGBA triangle. 869 * Interpolate S,T,R with perspective correction, w/out mipmapping. 870 */ 871#define NAME general_textured_triangle 872#define INTERP_Z 1 873#define INTERP_W 1 874#define INTERP_FOG 1 875#define INTERP_RGB 1 876#define INTERP_SPEC 1 877#define INTERP_ALPHA 1 878#define INTERP_TEX 1 879#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 880#include "s_tritemp.h" 881 882 883 884/* 885 * This is the big one! 886 * Interpolate Z, RGB, Alpha, specular, fog, and N sets of texture coordinates. 887 * Yup, it's slow. 888 */ 889#define NAME multitextured_triangle 890#define INTERP_Z 1 891#define INTERP_W 1 892#define INTERP_FOG 1 893#define INTERP_RGB 1 894#define INTERP_ALPHA 1 895#define INTERP_SPEC 1 896#define INTERP_MULTITEX 1 897#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span); 898#include "s_tritemp.h" 899 900 901 902/* 903 * Special tri function for occlusion testing 904 */ 905#define NAME occlusion_zless_triangle 906#define INTERP_Z 1 907#define SETUP_CODE \ 908 struct gl_renderbuffer *rb \ 909 = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; \ 910 ASSERT(ctx->Depth.Test); \ 911 ASSERT(!ctx->Depth.Mask); \ 912 ASSERT(ctx->Depth.Func == GL_LESS); \ 913 if (ctx->OcclusionResult && !ctx->Occlusion.Active) { \ 914 return; \ 915 } 916#define RENDER_SPAN( span ) \ 917 if (ctx->Visual.depthBits <= 16) { \ 918 GLuint i; \ 919 const GLushort *zRow = (const GLushort *) \ 920 rb->GetPointer(ctx, rb, span.x, span.y); \ 921 for (i = 0; i < span.end; i++) { \ 922 GLdepth z = FixedToDepth(span.z); \ 923 if (z < zRow[i]) { \ 924 ctx->OcclusionResult = GL_TRUE; \ 925 ctx->Occlusion.PassedCounter++; \ 926 } \ 927 span.z += span.zStep; \ 928 } \ 929 } \ 930 else { \ 931 GLuint i; \ 932 const GLuint *zRow = (const GLuint *) \ 933 rb->GetPointer(ctx, rb, span.x, span.y); \ 934 for (i = 0; i < span.end; i++) { \ 935 if ((GLuint)span.z < zRow[i]) { \ 936 ctx->OcclusionResult = GL_TRUE; \ 937 ctx->Occlusion.PassedCounter++; \ 938 } \ 939 span.z += span.zStep; \ 940 } \ 941 } 942#include "s_tritemp.h" 943 944 945 946static void 947nodraw_triangle( GLcontext *ctx, 948 const SWvertex *v0, 949 const SWvertex *v1, 950 const SWvertex *v2 ) 951{ 952 (void) (ctx && v0 && v1 && v2); 953} 954 955 956/* 957 * This is used when separate specular color is enabled, but not 958 * texturing. We add the specular color to the primary color, 959 * draw the triangle, then restore the original primary color. 960 * Inefficient, but seldom needed. 961 */ 962void _swrast_add_spec_terms_triangle( GLcontext *ctx, 963 const SWvertex *v0, 964 const SWvertex *v1, 965 const SWvertex *v2 ) 966{ 967 SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */ 968 SWvertex *ncv1 = (SWvertex *)v1; 969 SWvertex *ncv2 = (SWvertex *)v2; 970#if CHAN_TYPE == GL_FLOAT 971 GLfloat rSum, gSum, bSum; 972#else 973 GLint rSum, gSum, bSum; 974#endif 975 GLchan c[3][4]; 976 /* save original colors */ 977 COPY_CHAN4( c[0], ncv0->color ); 978 COPY_CHAN4( c[1], ncv1->color ); 979 COPY_CHAN4( c[2], ncv2->color ); 980 /* sum v0 */ 981 rSum = ncv0->color[0] + ncv0->specular[0]; 982 gSum = ncv0->color[1] + ncv0->specular[1]; 983 bSum = ncv0->color[2] + ncv0->specular[2]; 984 ncv0->color[0] = MIN2(rSum, CHAN_MAX); 985 ncv0->color[1] = MIN2(gSum, CHAN_MAX); 986 ncv0->color[2] = MIN2(bSum, CHAN_MAX); 987 /* sum v1 */ 988 rSum = ncv1->color[0] + ncv1->specular[0]; 989 gSum = ncv1->color[1] + ncv1->specular[1]; 990 bSum = ncv1->color[2] + ncv1->specular[2]; 991 ncv1->color[0] = MIN2(rSum, CHAN_MAX); 992 ncv1->color[1] = MIN2(gSum, CHAN_MAX); 993 ncv1->color[2] = MIN2(bSum, CHAN_MAX); 994 /* sum v2 */ 995 rSum = ncv2->color[0] + ncv2->specular[0]; 996 gSum = ncv2->color[1] + ncv2->specular[1]; 997 bSum = ncv2->color[2] + ncv2->specular[2]; 998 ncv2->color[0] = MIN2(rSum, CHAN_MAX); 999 ncv2->color[1] = MIN2(gSum, CHAN_MAX); 1000 ncv2->color[2] = MIN2(bSum, CHAN_MAX); 1001 /* draw */ 1002 SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 ); 1003 /* restore original colors */ 1004 COPY_CHAN4( ncv0->color, c[0] ); 1005 COPY_CHAN4( ncv1->color, c[1] ); 1006 COPY_CHAN4( ncv2->color, c[2] ); 1007} 1008 1009 1010 1011#ifdef DEBUG 1012 1013/* record the current triangle function name */ 1014const char *_mesa_triFuncName = NULL; 1015 1016#define USE(triFunc) \ 1017do { \ 1018 _mesa_triFuncName = #triFunc; \ 1019 /*printf("%s\n", _mesa_triFuncName);*/ \ 1020 swrast->Triangle = triFunc; \ 1021} while (0) 1022 1023#else 1024 1025#define USE(triFunc) swrast->Triangle = triFunc; 1026 1027#endif 1028 1029 1030 1031 1032/* 1033 * Determine which triangle rendering function to use given the current 1034 * rendering context. 1035 * 1036 * Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or 1037 * remove tests to this code. 1038 */ 1039void 1040_swrast_choose_triangle( GLcontext *ctx ) 1041{ 1042 SWcontext *swrast = SWRAST_CONTEXT(ctx); 1043 const GLboolean rgbmode = ctx->Visual.rgbMode; 1044 1045 if (ctx->Polygon.CullFlag && 1046 ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) { 1047 USE(nodraw_triangle); 1048 return; 1049 } 1050 1051 if (ctx->RenderMode==GL_RENDER) { 1052 1053 if (ctx->Polygon.SmoothFlag) { 1054 _swrast_set_aa_triangle_function(ctx); 1055 ASSERT(swrast->Triangle); 1056 return; 1057 } 1058 1059 /* special case for occlusion testing */ 1060 if ((ctx->Depth.OcclusionTest || ctx->Occlusion.Active) && 1061 ctx->Depth.Test && 1062 ctx->Depth.Mask == GL_FALSE && 1063 ctx->Depth.Func == GL_LESS && 1064 !ctx->Stencil.Enabled) { 1065 if ((rgbmode && 1066 ctx->Color.ColorMask[0] == 0 && 1067 ctx->Color.ColorMask[1] == 0 && 1068 ctx->Color.ColorMask[2] == 0 && 1069 ctx->Color.ColorMask[3] == 0) 1070 || 1071 (!rgbmode && ctx->Color.IndexMask == 0)) { 1072 USE(occlusion_zless_triangle); 1073 return; 1074 } 1075 } 1076 1077 if (ctx->Texture._EnabledCoordUnits || ctx->FragmentProgram._Active) { 1078 /* Ugh, we do a _lot_ of tests to pick the best textured tri func */ 1079 const struct gl_texture_object *texObj2D; 1080 const struct gl_texture_image *texImg; 1081 GLenum minFilter, magFilter, envMode; 1082 GLint format; 1083 texObj2D = ctx->Texture.Unit[0].Current2D; 1084 texImg = texObj2D ? texObj2D->Image[0][texObj2D->BaseLevel] : NULL; 1085 format = texImg ? texImg->TexFormat->MesaFormat : -1; 1086 minFilter = texObj2D ? texObj2D->MinFilter : (GLenum) 0; 1087 magFilter = texObj2D ? texObj2D->MagFilter : (GLenum) 0; 1088 envMode = ctx->Texture.Unit[0].EnvMode; 1089 1090 /* First see if we can use an optimized 2-D texture function */ 1091 if (ctx->Texture._EnabledCoordUnits == 0x1 1092 && !ctx->FragmentProgram._Active 1093 && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT 1094 && texObj2D->WrapS == GL_REPEAT 1095 && texObj2D->WrapT == GL_REPEAT 1096 && texObj2D->_IsPowerOfTwo 1097 && texImg->Border == 0 1098 && texImg->Width == texImg->RowStride 1099 && (format == MESA_FORMAT_RGB || format == MESA_FORMAT_RGBA) 1100 && minFilter == magFilter 1101 && ctx->Light.Model.ColorControl == GL_SINGLE_COLOR 1102 && ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT) { 1103 if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) { 1104 if (minFilter == GL_NEAREST 1105 && format == MESA_FORMAT_RGB 1106 && (envMode == GL_REPLACE || envMode == GL_DECAL) 1107 && ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT) 1108 && ctx->Depth.Func == GL_LESS 1109 && ctx->Depth.Mask == GL_TRUE) 1110 || swrast->_RasterMask == TEXTURE_BIT) 1111 && ctx->Polygon.StippleFlag == GL_FALSE 1112 && ctx->Visual.depthBits <= 16) { 1113 if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) { 1114 USE(simple_z_textured_triangle); 1115 } 1116 else { 1117 USE(simple_textured_triangle); 1118 } 1119 } 1120 else { 1121#if (CHAN_BITS == 16 || CHAN_BITS == 32) 1122 USE(general_textured_triangle); 1123#else 1124 USE(affine_textured_triangle); 1125#endif 1126 } 1127 } 1128 else { 1129#if (CHAN_BITS == 16 || CHAN_BITS == 32) 1130 USE(general_textured_triangle); 1131#else 1132 USE(persp_textured_triangle); 1133#endif 1134 } 1135 } 1136 else { 1137 /* general case textured triangles */ 1138 if (ctx->Texture._EnabledCoordUnits > 1) { 1139 USE(multitextured_triangle); 1140 } 1141 else { 1142 USE(general_textured_triangle); 1143 } 1144 } 1145 } 1146 else { 1147 ASSERT(!ctx->Texture._EnabledCoordUnits); 1148 if (ctx->Light.ShadeModel==GL_SMOOTH) { 1149 /* smooth shaded, no texturing, stippled or some raster ops */ 1150 if (rgbmode) { 1151 USE(smooth_rgba_triangle); 1152 } 1153 else { 1154 USE(smooth_ci_triangle); 1155 } 1156 } 1157 else { 1158 /* flat shaded, no texturing, stippled or some raster ops */ 1159 if (rgbmode) { 1160 USE(flat_rgba_triangle); 1161 } 1162 else { 1163 USE(flat_ci_triangle); 1164 } 1165 } 1166 } 1167 } 1168 else if (ctx->RenderMode==GL_FEEDBACK) { 1169 USE(_swrast_feedback_triangle); 1170 } 1171 else { 1172 /* GL_SELECT mode */ 1173 USE(_swrast_select_triangle); 1174 } 1175} 1176