1 /* $Id: texture.c,v 1.36 1997/11/17 02:04:06 brianp Exp $ */ 2 3 /* 4 * Mesa 3-D graphics library 5 * Version: 2.5 6 * Copyright (C) 1995-1997 Brian Paul 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with this library; if not, write to the Free 20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 24 /* 25 * $Log: texture.c,v $ 26 * Revision 1.36 1997/11/17 02:04:06 brianp 27 * fixed a typo in texture code 28 * 29 * Revision 1.35 1997/11/13 02:17:32 brianp 30 * added a few const keywords 31 * 32 * Revision 1.34 1997/10/16 01:59:08 brianp 33 * added GL_EXT_shared_texture_palette extension 34 * 35 * Revision 1.33 1997/09/27 00:14:39 brianp 36 * added GL_EXT_paletted_texture extension 37 * 38 * Revision 1.32 1997/08/14 01:03:12 brianp 39 * fixed small bug in GL_SPHERE_MAP texgen (Petri Nordlund) 40 * 41 * Revision 1.31 1997/07/24 01:25:34 brianp 42 * changed precompiled header symbol from PCH to PC_HEADER 43 * 44 * Revision 1.30 1997/07/22 01:23:48 brianp 45 * fixed negative texture coord sampling problem (Magnus Lundin) 46 * 47 * Revision 1.29 1997/07/09 00:32:26 brianp 48 * fixed bug involving sampling and incomplete texture objects 49 * 50 * Revision 1.28 1997/05/28 03:26:49 brianp 51 * added precompiled header (PCH) support 52 * 53 * Revision 1.27 1997/05/17 03:51:10 brianp 54 * fixed bug in PROD macro (Waldemar Celes) 55 * 56 * Revision 1.26 1997/05/03 00:53:56 brianp 57 * all-new texture sampling via gl_texture_object's SampleFunc pointer 58 * 59 * Revision 1.25 1997/05/01 01:40:14 brianp 60 * replaced sqrt() with GL_SQRT, use NORMALIZE_3FV instead of NORMALIZE_3V 61 * 62 * Revision 1.24 1997/04/28 02:04:18 brianp 63 * GL_SPHERE_MAP texgen was wrong (Eamon O'Dea) 64 * 65 * Revision 1.23 1997/04/20 20:29:11 brianp 66 * replaced abort() with gl_problem() 67 * 68 * Revision 1.22 1997/04/16 23:56:41 brianp 69 * added a few #include files 70 * 71 * Revision 1.21 1997/04/14 02:02:39 brianp 72 * moved many functions into new texstate.c file 73 * 74 * Revision 1.20 1997/04/01 04:19:14 brianp 75 * call gl_analyze_modelview_matrix instead of gl_compute_modelview_inverse 76 * 77 * Revision 1.19 1997/03/04 19:55:58 brianp 78 * small texture sampling optimizations. better comments. 79 * 80 * Revision 1.18 1997/03/04 19:19:20 brianp 81 * fixed a number of problems with texture borders 82 * 83 * Revision 1.17 1997/02/27 19:58:08 brianp 84 * call gl_problem() instead of gl_warning() 85 * 86 * Revision 1.16 1997/02/09 19:53:43 brianp 87 * now use TEXTURE_xD enable constants 88 * 89 * Revision 1.15 1997/02/09 18:53:14 brianp 90 * added GL_EXT_texture3D support 91 * 92 * Revision 1.14 1997/01/30 21:06:03 brianp 93 * added some missing glGetTexLevelParameter() GLenums 94 * 95 * Revision 1.13 1997/01/16 03:36:01 brianp 96 * added calls to device driver TexParameter() and TexEnv() functions 97 * 98 * Revision 1.12 1997/01/09 19:48:30 brianp 99 * better error checking 100 * added gl_texturing_enabled() 101 * 102 * Revision 1.11 1996/12/20 20:22:30 brianp 103 * linear interpolation between mipmap levels was reverse weighted 104 * max mipmap level was incorrectly tested for 105 * 106 * Revision 1.10 1996/12/12 22:33:05 brianp 107 * minor changes to gl_texgen() 108 * 109 * Revision 1.9 1996/12/07 10:35:41 brianp 110 * implmented glGetTexGen*() functions 111 * 112 * Revision 1.8 1996/11/14 01:03:09 brianp 113 * removed const's from gl_texgen() function to avoid VMS compiler warning 114 * 115 * Revision 1.7 1996/11/08 02:19:52 brianp 116 * gl_do_texgen() replaced with gl_texgen() 117 * 118 * Revision 1.6 1996/10/26 17:17:30 brianp 119 * glTexGen GL_EYE_PLANE vector now transformed by inverse modelview matrix 120 * 121 * Revision 1.5 1996/10/11 03:42:38 brianp 122 * replaced old _EXT symbols 123 * 124 * Revision 1.4 1996/09/27 01:30:24 brianp 125 * added missing default cases to switches 126 * 127 * Revision 1.3 1996/09/15 14:18:55 brianp 128 * now use GLframebuffer and GLvisual 129 * 130 * Revision 1.2 1996/09/15 01:48:58 brianp 131 * removed #define NULL 0 132 * 133 * Revision 1.1 1996/09/13 01:38:16 brianp 134 * Initial revision 135 * 136 */ 137 138 139 #ifdef PC_HEADER 140 #include "all.h" 141 #else 142 #include <math.h> 143 #include <stdlib.h> 144 #include "context.h" 145 #include "macros.h" 146 #include "mmath.h" 147 #include "pb.h" 148 #include "texture.h" 149 #include "types.h" 150 #endif 151 152 153 154 /* 155 * Perform automatic texture coordinate generation. 156 * Input: ctx - the context 157 * n - number of texture coordinates to generate 158 * obj - array of vertexes in object coordinate system 159 * eye - array of vertexes in eye coordinate system 160 * normal - array of normal vectores in eye coordinate system 161 * Output: texcoord - array of resuling texture coordinates 162 */ 163 void gl_texgen( GLcontext *ctx, GLint n, 164 GLfloat obj[][4], GLfloat eye[][4], 165 GLfloat normal[][3], GLfloat texcoord[][4] ) 166 { 167 /* special case: S and T sphere mapping */ 168 if (ctx->Texture.TexGenEnabled==(S_BIT|T_BIT) 169 && ctx->Texture.GenModeS==GL_SPHERE_MAP 170 && ctx->Texture.GenModeT==GL_SPHERE_MAP) { 171 GLint i; 172 for (i=0;i<n;i++) { 173 GLfloat u[3], two_nu, m, fx, fy, fz; 174 COPY_3V( u, eye[i] ); 175 NORMALIZE_3FV( u ); 176 two_nu = 2.0F * DOT3(normal[i],u); 177 fx = u[0] - normal[i][0] * two_nu; 178 fy = u[1] - normal[i][1] * two_nu; 179 fz = u[2] - normal[i][2] * two_nu; 180 m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0F)*(fz+1.0F) ); 181 if (m==0.0F) { 182 texcoord[i][0] = 0.5F; 183 texcoord[i][1] = 0.5F; 184 } 185 else { 186 GLfloat mInv = 1.0F / m; 187 texcoord[i][0] = fx * mInv + 0.5F; 188 texcoord[i][1] = fy * mInv + 0.5F; 189 } 190 } 191 return; 192 } 193 194 /* general solution */ 195 if (ctx->Texture.TexGenEnabled & S_BIT) { 196 GLint i; 197 switch (ctx->Texture.GenModeS) { 198 case GL_OBJECT_LINEAR: 199 for (i=0;i<n;i++) { 200 texcoord[i][0] = DOT4( obj[i], ctx->Texture.ObjectPlaneS ); 201 } 202 break; 203 case GL_EYE_LINEAR: 204 for (i=0;i<n;i++) { 205 texcoord[i][0] = DOT4( eye[i], ctx->Texture.EyePlaneS ); 206 } 207 break; 208 case GL_SPHERE_MAP: 209 for (i=0;i<n;i++) { 210 GLfloat u[3], two_nu, m, fx, fy, fz; 211 COPY_3V( u, eye[i] ); 212 NORMALIZE_3FV( u ); 213 two_nu = 2.0*DOT3(normal[i],u); 214 fx = u[0] - normal[i][0] * two_nu; 215 fy = u[1] - normal[i][1] * two_nu; 216 fz = u[2] - normal[i][2] * two_nu; 217 m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0)*(fz+1.0) ); 218 if (m==0.0F) { 219 texcoord[i][0] = 0.5F; 220 } 221 else { 222 texcoord[i][0] = fx / m + 0.5F; 223 } 224 } 225 break; 226 default: 227 gl_problem(ctx, "Bad S texgen"); 228 return; 229 } 230 } 231 232 if (ctx->Texture.TexGenEnabled & T_BIT) { 233 GLint i; 234 switch (ctx->Texture.GenModeT) { 235 case GL_OBJECT_LINEAR: 236 for (i=0;i<n;i++) { 237 texcoord[i][1] = DOT4( obj[i], ctx->Texture.ObjectPlaneT ); 238 } 239 break; 240 case GL_EYE_LINEAR: 241 for (i=0;i<n;i++) { 242 texcoord[i][1] = DOT4( eye[i], ctx->Texture.EyePlaneT ); 243 } 244 break; 245 case GL_SPHERE_MAP: 246 for (i=0;i<n;i++) { 247 GLfloat u[3], two_nu, m, fx, fy, fz; 248 COPY_3V( u, eye[i] ); 249 NORMALIZE_3FV( u ); 250 two_nu = 2.0*DOT3(normal[i],u); 251 fx = u[0] - normal[i][0] * two_nu; 252 fy = u[1] - normal[i][1] * two_nu; 253 fz = u[2] - normal[i][2] * two_nu; 254 m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0)*(fz+1.0) ); 255 if (m==0.0F) { 256 texcoord[i][1] = 0.5F; 257 } 258 else { 259 texcoord[i][1] = fy / m + 0.5F; 260 } 261 } 262 break; 263 default: 264 gl_problem(ctx, "Bad T texgen"); 265 return; 266 } 267 } 268 269 if (ctx->Texture.TexGenEnabled & R_BIT) { 270 GLint i; 271 switch (ctx->Texture.GenModeR) { 272 case GL_OBJECT_LINEAR: 273 for (i=0;i<n;i++) { 274 texcoord[i][2] = DOT4( obj[i], ctx->Texture.ObjectPlaneR ); 275 } 276 break; 277 case GL_EYE_LINEAR: 278 for (i=0;i<n;i++) { 279 texcoord[i][2] = DOT4( eye[i], ctx->Texture.EyePlaneR ); 280 } 281 break; 282 default: 283 gl_problem(ctx, "Bad R texgen"); 284 return; 285 } 286 } 287 288 if (ctx->Texture.TexGenEnabled & Q_BIT) { 289 GLint i; 290 switch (ctx->Texture.GenModeQ) { 291 case GL_OBJECT_LINEAR: 292 for (i=0;i<n;i++) { 293 texcoord[i][3] = DOT4( obj[i], ctx->Texture.ObjectPlaneQ ); 294 } 295 break; 296 case GL_EYE_LINEAR: 297 for (i=0;i<n;i++) { 298 texcoord[i][3] = DOT4( eye[i], ctx->Texture.EyePlaneQ ); 299 } 300 break; 301 default: 302 gl_problem(ctx, "Bad Q texgen"); 303 return; 304 } 305 } 306 } 307 308 309 310 /* 311 * Paletted texture sampling. 312 * Input: tObj - the texture object 313 * index - the palette index (8-bit only) 314 * Output: red, green, blue, alpha - the texel color 315 */ 316 static void palette_sample(const struct gl_texture_object *tObj, 317 GLubyte index, GLubyte *red, GLubyte *green, 318 GLubyte *blue, GLubyte *alpha) 319 { 320 GLint i = index; 321 const GLubyte *palette; 322 323 palette = tObj->Palette; 324 325 switch (tObj->PaletteFormat) { 326 case GL_ALPHA: 327 *alpha = tObj->Palette[index]; 328 return; 329 case GL_LUMINANCE: 330 case GL_INTENSITY: 331 *red = palette[index]; 332 return; 333 case GL_LUMINANCE_ALPHA: 334 *red = palette[(index << 1) + 0]; 335 *alpha = palette[(index << 1) + 1]; 336 return; 337 case GL_RGB: 338 *red = palette[index * 3 + 0]; 339 *green = palette[index * 3 + 1]; 340 *blue = palette[index * 3 + 2]; 341 return; 342 case GL_RGBA: 343 *red = palette[(i << 2) + 0]; 344 *green = palette[(i << 2) + 1]; 345 *blue = palette[(i << 2) + 2]; 346 *alpha = palette[(i << 2) + 3]; 347 return; 348 default: 349 gl_problem(NULL, "Bad palette format in palette_sample"); 350 } 351 } 352 353 354 355 356 /**********************************************************************/ 357 /* 1-D Texture Sampling Functions */ 358 /**********************************************************************/ 359 360 361 /* 362 * Return the fractional part of x. 363 */ 364 #define frac(x) ((GLfloat)(x)-floor((GLfloat)x)) 365 366 367 368 /* 369 * Given 1-D texture image and an (i) texel column coordinate, return the 370 * texel color. 371 */ 372 static void get_1d_texel( const struct gl_texture_object *tObj, 373 const struct gl_texture_image *img, GLint i, 374 GLubyte *red, GLubyte *green, GLubyte *blue, 375 GLubyte *alpha ) 376 { 377 GLubyte *texel; 378 379 #ifdef DEBUG 380 GLint width = img->Width; 381 if (i<0 || i>=width) abort(); 382 #endif 383 384 switch (img->Format) { 385 case GL_COLOR_INDEX: 386 { 387 GLubyte index = img->Data[i]; 388 palette_sample(tObj, index, red, green, blue, alpha); 389 return; 390 } 391 return; 392 case GL_ALPHA: 393 *alpha = img->Data[ i ]; 394 return; 395 case GL_LUMINANCE: 396 case GL_INTENSITY: 397 *red = img->Data[ i ]; 398 return; 399 case GL_LUMINANCE_ALPHA: 400 texel = img->Data + i * 2; 401 *red = texel[0]; 402 *alpha = texel[1]; 403 return; 404 case GL_RGB: 405 texel = img->Data + i * 3; 406 *red = texel[0]; 407 *green = texel[1]; 408 *blue = texel[2]; 409 return; 410 case GL_RGBA: 411 texel = img->Data + i * 4; 412 *red = texel[0]; 413 *green = texel[1]; 414 *blue = texel[2]; 415 *alpha = texel[3]; 416 return; 417 default: 418 gl_problem(NULL, "Bad format in get_1d_texel"); 419 return; 420 } 421 } 422 423 424 425 /* 426 * Return the texture sample for coordinate (s) using GL_NEAREST filter. 427 */ 428 static void sample_1d_nearest( const struct gl_texture_object *tObj, 429 const struct gl_texture_image *img, 430 GLfloat s, 431 GLubyte *red, GLubyte *green, 432 GLubyte *blue, GLubyte *alpha ) 433 { 434 GLint width = img->Width2; /* without border, power of two */ 435 GLint i; 436 GLubyte *texel; 437 438 /* Clamp/Repeat S and convert to integer texel coordinate */ 439 if (tObj->WrapS==GL_REPEAT) { 440 /* s limited to [0,1) */ 441 /* i limited to [0,width-1] */ 442 i = (GLint) (s * width); 443 if (s<0.0F) i -= 1; 444 i &= (width-1); 445 } 446 else { 447 /* s limited to [0,1] */ 448 /* i limited to [0,width-1] */ 449 if (s<0.0F) i = 0; 450 else if (s>1.0F) i = width-1; 451 else i = (GLint) (s * width); 452 } 453 454 /* skip over the border, if any */ 455 i += img->Border; 456 457 /* Get the texel */ 458 switch (img->Format) { 459 case GL_COLOR_INDEX: 460 { 461 GLubyte index = img->Data[i]; 462 palette_sample(tObj, index, red, green, blue, alpha); 463 return; 464 } 465 case GL_ALPHA: 466 *alpha = img->Data[i]; 467 return; 468 case GL_LUMINANCE: 469 case GL_INTENSITY: 470 *red = img->Data[i]; 471 return; 472 case GL_LUMINANCE_ALPHA: 473 texel = img->Data + i * 2; 474 *red = texel[0]; 475 *alpha = texel[1]; 476 return; 477 case GL_RGB: 478 texel = img->Data + i * 3; 479 *red = texel[0]; 480 *green = texel[1]; 481 *blue = texel[2]; 482 return; 483 case GL_RGBA: 484 texel = img->Data + i * 4; 485 *red = texel[0]; 486 *green = texel[1]; 487 *blue = texel[2]; 488 *alpha = texel[3]; 489 return; 490 default: 491 gl_problem(NULL, "Bad format in sample_1d_nearest"); 492 } 493 } 494 495 496 497 /* 498 * Return the texture sample for coordinate (s) using GL_LINEAR filter. 499 */ 500 static void sample_1d_linear( const struct gl_texture_object *tObj, 501 const struct gl_texture_image *img, 502 GLfloat s, 503 GLubyte *red, GLubyte *green, 504 GLubyte *blue, GLubyte *alpha ) 505 { 506 GLint width = img->Width2; 507 GLint i0, i1; 508 GLfloat u; 509 GLint i0border, i1border; 510 511 u = s * width; 512 if (tObj->WrapS==GL_REPEAT) { 513 i0 = ((GLint) floor(u - 0.5F)) % width; 514 i1 = (i0 + 1) & (width-1); 515 i0border = i1border = 0; 516 } 517 else { 518 i0 = (GLint) floor(u - 0.5F); 519 i1 = i0 + 1; 520 i0border = (i0<0) | (i0>=width); 521 i1border = (i1<0) | (i1>=width); 522 } 523 524 if (img->Border) { 525 i0 += img->Border; 526 i1 += img->Border; 527 i0border = i1border = 0; 528 } 529 else { 530 i0 &= (width-1); 531 } 532 533 { 534 GLfloat a = frac(u - 0.5F); 535 536 GLint w0 = (GLint) ((1.0F-a) * 256.0F); 537 GLint w1 = (GLint) ( a * 256.0F); 538 539 GLubyte red0, green0, blue0, alpha0; 540 GLubyte red1, green1, blue1, alpha1; 541 542 if (i0border) { 543 red0 = tObj->BorderColor[0]; 544 green0 = tObj->BorderColor[1]; 545 blue0 = tObj->BorderColor[2]; 546 alpha0 = tObj->BorderColor[3]; 547 } 548 else { 549 get_1d_texel( tObj, img, i0, &red0, &green0, &blue0, &alpha0 ); 550 } 551 if (i1border) { 552 red1 = tObj->BorderColor[0]; 553 green1 = tObj->BorderColor[1]; 554 blue1 = tObj->BorderColor[2]; 555 alpha1 = tObj->BorderColor[3]; 556 } 557 else { 558 get_1d_texel( tObj, img, i1, &red1, &green1, &blue1, &alpha1 ); 559 } 560 561 *red = (w0*red0 + w1*red1) >> 8; 562 *green = (w0*green0 + w1*green1) >> 8; 563 *blue = (w0*blue0 + w1*blue1) >> 8; 564 *alpha = (w0*alpha0 + w1*alpha1) >> 8; 565 } 566 } 567 568 569 static void 570 sample_1d_nearest_mipmap_nearest( const struct gl_texture_object *tObj, 571 GLfloat s, GLfloat lambda, 572 GLubyte *red, GLubyte *green, 573 GLubyte *blue, GLubyte *alpha ) 574 { 575 GLint level; 576 if (lambda<=0.5F) { 577 level = 0; 578 } 579 else { 580 GLint widthlog2 = tObj->Image[0]->WidthLog2; 581 level = (GLint) (lambda + 0.499999F); 582 if (level>widthlog2 ) { 583 level = widthlog2; 584 } 585 } 586 sample_1d_nearest( tObj, tObj->Image[level], 587 s, red, green, blue, alpha ); 588 } 589 590 591 static void 592 sample_1d_linear_mipmap_nearest( const struct gl_texture_object *tObj, 593 GLfloat s, GLfloat lambda, 594 GLubyte *red, GLubyte *green, 595 GLubyte *blue, GLubyte *alpha ) 596 { 597 GLint level; 598 if (lambda<=0.5F) { 599 level = 0; 600 } 601 else { 602 GLint widthlog2 = tObj->Image[0]->WidthLog2; 603 level = (GLint) (lambda + 0.499999F); 604 if (level>widthlog2 ) { 605 level = widthlog2; 606 } 607 } 608 sample_1d_linear( tObj, tObj->Image[level], 609 s, red, green, blue, alpha ); 610 } 611 612 613 614 static void 615 sample_1d_nearest_mipmap_linear( const struct gl_texture_object *tObj, 616 GLfloat s, GLfloat lambda, 617 GLubyte *red, GLubyte *green, 618 GLubyte *blue, GLubyte *alpha ) 619 { 620 GLint max = tObj->Image[0]->MaxLog2; 621 622 if (lambda>=max) { 623 sample_1d_nearest( tObj, tObj->Image[max], 624 s, red, green, blue, alpha ); 625 } 626 else { 627 GLubyte red0, green0, blue0, alpha0; 628 GLubyte red1, green1, blue1, alpha1; 629 GLfloat f = frac(lambda); 630 GLint level = (GLint) (lambda + 1.0F); 631 level = CLAMP( level, 1, max ); 632 sample_1d_nearest( tObj, tObj->Image[level-1], 633 s, &red0, &green0, &blue0, &alpha0 ); 634 sample_1d_nearest( tObj, tObj->Image[level], 635 s, &red1, &green1, &blue1, &alpha1 ); 636 *red = (1.0F-f)*red0 + f*red1; 637 *green = (1.0F-f)*green0 + f*green1; 638 *blue = (1.0F-f)*blue0 + f*blue1; 639 *alpha = (1.0F-f)*alpha0 + f*alpha1; 640 } 641 } 642 643 644 645 static void 646 sample_1d_linear_mipmap_linear( const struct gl_texture_object *tObj, 647 GLfloat s, GLfloat lambda, 648 GLubyte *red, GLubyte *green, 649 GLubyte *blue, GLubyte *alpha ) 650 { 651 GLint max = tObj->Image[0]->MaxLog2; 652 653 if (lambda>=max) { 654 sample_1d_linear( tObj, tObj->Image[max], 655 s, red, green, blue, alpha ); 656 } 657 else { 658 GLubyte red0, green0, blue0, alpha0; 659 GLubyte red1, green1, blue1, alpha1; 660 GLfloat f = frac(lambda); 661 GLint level = (GLint) (lambda + 1.0F); 662 level = CLAMP( level, 1, max ); 663 sample_1d_linear( tObj, tObj->Image[level-1], 664 s, &red0, &green0, &blue0, &alpha0 ); 665 sample_1d_linear( tObj, tObj->Image[level], 666 s, &red1, &green1, &blue1, &alpha1 ); 667 *red = (1.0F-f)*red0 + f*red1; 668 *green = (1.0F-f)*green0 + f*green1; 669 *blue = (1.0F-f)*blue0 + f*blue1; 670 *alpha = (1.0F-f)*alpha0 + f*alpha1; 671 } 672 } 673 674 675 676 static void sample_nearest_1d( const struct gl_texture_object *tObj, GLuint n, 677 const GLfloat s[], const GLfloat t[], 678 const GLfloat u[], const GLfloat lambda[], 679 GLubyte red[], GLubyte green[], GLubyte blue[], 680 GLubyte alpha[] ) 681 { 682 GLuint i; 683 for (i=0;i<n;i++) { 684 sample_1d_nearest( tObj, tObj->Image[0], s[i], 685 &red[i], &green[i], &blue[i], &alpha[i]); 686 } 687 } 688 689 690 691 static void sample_linear_1d( const struct gl_texture_object *tObj, GLuint n, 692 const GLfloat s[], const GLfloat t[], 693 const GLfloat u[], const GLfloat lambda[], 694 GLubyte red[], GLubyte green[], GLubyte blue[], 695 GLubyte alpha[] ) 696 { 697 GLuint i; 698 for (i=0;i<n;i++) { 699 sample_1d_linear( tObj, tObj->Image[0], s[i], 700 &red[i], &green[i], &blue[i], &alpha[i]); 701 } 702 } 703 704 705 /* 706 * Given an (s) texture coordinate and lambda (level of detail) value, 707 * return a texture sample. 708 * 709 */ 710 static void sample_lambda_1d( const struct gl_texture_object *tObj, GLuint n, 711 const GLfloat s[], const GLfloat t[], 712 const GLfloat u[], const GLfloat lambda[], 713 GLubyte red[], GLubyte green[], GLubyte blue[], 714 GLubyte alpha[] ) 715 { 716 GLuint i; 717 718 for (i=0;i<n;i++) { 719 if (lambda[i] > tObj->MinMagThresh) { 720 /* minification */ 721 switch (tObj->MinFilter) { 722 case GL_NEAREST: 723 sample_1d_nearest( tObj, tObj->Image[0], s[i], 724 &red[i], &green[i], &blue[i], &alpha[i] ); 725 break; 726 case GL_LINEAR: 727 sample_1d_linear( tObj, tObj->Image[0], s[i], 728 &red[i], &green[i], &blue[i], &alpha[i] ); 729 break; 730 case GL_NEAREST_MIPMAP_NEAREST: 731 sample_1d_nearest_mipmap_nearest( tObj, lambda[i], s[i], 732 &red[i], &green[i], &blue[i], &alpha[i] ); 733 break; 734 case GL_LINEAR_MIPMAP_NEAREST: 735 sample_1d_linear_mipmap_nearest( tObj, s[i], lambda[i], 736 &red[i], &green[i], &blue[i], &alpha[i] ); 737 break; 738 case GL_NEAREST_MIPMAP_LINEAR: 739 sample_1d_nearest_mipmap_linear( tObj, s[i], lambda[i], 740 &red[i], &green[i], &blue[i], &alpha[i] ); 741 break; 742 case GL_LINEAR_MIPMAP_LINEAR: 743 sample_1d_linear_mipmap_linear( tObj, s[i], lambda[i], 744 &red[i], &green[i], &blue[i], &alpha[i] ); 745 break; 746 default: 747 gl_problem(NULL, "Bad min filter in sample_1d_texture"); 748 return; 749 } 750 } 751 else { 752 /* magnification */ 753 switch (tObj->MagFilter) { 754 case GL_NEAREST: 755 sample_1d_nearest( tObj, tObj->Image[0], s[i], 756 &red[i], &green[i], &blue[i], &alpha[i] ); 757 break; 758 case GL_LINEAR: 759 sample_1d_linear( tObj, tObj->Image[0], s[i], 760 &red[i], &green[i], &blue[i], &alpha[i] ); 761 break; 762 default: 763 gl_problem(NULL, "Bad mag filter in sample_1d_texture"); 764 return; 765 } 766 } 767 } 768 } 769 770 771 772 773 /**********************************************************************/ 774 /* 2-D Texture Sampling Functions */ 775 /**********************************************************************/ 776 777 778 /* 779 * Given a texture image and an (i,j) integer texel coordinate, return the 780 * texel color. 781 */ 782 static void get_2d_texel( const struct gl_texture_object *tObj, 783 const struct gl_texture_image *img, GLint i, GLint j, 784 GLubyte *red, GLubyte *green, GLubyte *blue, 785 GLubyte *alpha ) 786 { 787 GLint width = img->Width; /* includes border */ 788 GLubyte *texel; 789 790 #ifdef DEBUG 791 GLint height = img->Height; /* includes border */ 792 if (i<0 || i>=width) abort(); 793 if (j<0 || j>=height) abort(); 794 #endif 795 796 switch (img->Format) { 797 case GL_COLOR_INDEX: 798 { 799 GLubyte index = img->Data[ width *j + i ]; 800 palette_sample(tObj, index, red, green, blue, alpha); 801 return; 802 } 803 case GL_ALPHA: 804 *alpha = img->Data[ width * j + i ]; 805 return; 806 case GL_LUMINANCE: 807 case GL_INTENSITY: 808 *red = img->Data[ width * j + i ]; 809 return; 810 case GL_LUMINANCE_ALPHA: 811 texel = img->Data + (width * j + i) * 2; 812 *red = texel[0]; 813 *alpha = texel[1]; 814 return; 815 case GL_RGB: 816 texel = img->Data + (width * j + i) * 3; 817 *red = texel[0]; 818 *green = texel[1]; 819 *blue = texel[2]; 820 return; 821 case GL_RGBA: 822 texel = img->Data + (width * j + i) * 4; 823 *red = texel[0]; 824 *green = texel[1]; 825 *blue = texel[2]; 826 *alpha = texel[3]; 827 return; 828 default: 829 gl_problem(NULL, "Bad format in get_2d_texel"); 830 } 831 } 832 833 834 835 /* 836 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. 837 */ 838 static void sample_2d_nearest( const struct gl_texture_object *tObj, 839 const struct gl_texture_image *img, 840 GLfloat s, GLfloat t, 841 GLubyte *red, GLubyte *green, 842 GLubyte *blue, GLubyte *alpha ) 843 { 844 GLint imgWidth = img->Width; /* includes border */ 845 GLint width = img->Width2; /* without border, power of two */ 846 GLint height = img->Height2; /* without border, power of two */ 847 GLint i, j; 848 GLubyte *texel; 849 850 /* Clamp/Repeat S and convert to integer texel coordinate */ 851 if (tObj->WrapS==GL_REPEAT) { 852 /* s limited to [0,1) */ 853 /* i limited to [0,width-1] */ 854 i = (GLint) (s * width); 855 if (s<0.0F) i -= 1; 856 i &= (width-1); 857 } 858 else { 859 /* s limited to [0,1] */ 860 /* i limited to [0,width-1] */ 861 if (s<=0.0F) i = 0; 862 else if (s>1.0F) i = width-1; 863 else i = (GLint) (s * width); 864 } 865 866 /* Clamp/Repeat T and convert to integer texel coordinate */ 867 if (tObj->WrapT==GL_REPEAT) { 868 /* t limited to [0,1) */ 869 /* j limited to [0,height-1] */ 870 j = (GLint) (t * height); 871 if (t<0.0F) j -= 1; 872 j &= (height-1); 873 } 874 else { 875 /* t limited to [0,1] */ 876 /* j limited to [0,height-1] */ 877 if (t<=0.0F) j = 0; 878 else if (t>1.0F) j = height-1; 879 else j = (GLint) (t * height); 880 } 881 882 /* skip over the border, if any */ 883 i += img->Border; 884 j += img->Border; 885 886 switch (img->Format) { 887 case GL_COLOR_INDEX: 888 { 889 GLubyte index = img->Data[ j * imgWidth + i ]; 890 palette_sample(tObj, index, red, green, blue, alpha); 891 return; 892 } 893 case GL_ALPHA: 894 *alpha = img->Data[ j * imgWidth + i ]; 895 return; 896 case GL_LUMINANCE: 897 case GL_INTENSITY: 898 *red = img->Data[ j * imgWidth + i ]; 899 return; 900 case GL_LUMINANCE_ALPHA: 901 texel = img->Data + ((j * imgWidth + i) << 1); 902 *red = texel[0]; 903 *alpha = texel[1]; 904 return; 905 case GL_RGB: 906 texel = img->Data + (j * imgWidth + i) * 3; 907 *red = texel[0]; 908 *green = texel[1]; 909 *blue = texel[2]; 910 return; 911 case GL_RGBA: 912 texel = img->Data + ((j * imgWidth + i) << 2); 913 *red = texel[0]; 914 *green = texel[1]; 915 *blue = texel[2]; 916 *alpha = texel[3]; 917 return; 918 default: 919 gl_problem(NULL, "Bad format in sample_2d_nearest"); 920 } 921 } 922 923 924 925 /* 926 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. 927 */ 928 static void sample_2d_linear( const struct gl_texture_object *tObj, 929 const struct gl_texture_image *img, 930 GLfloat s, GLfloat t, 931 GLubyte *red, GLubyte *green, 932 GLubyte *blue, GLubyte *alpha ) 933 { 934 GLint width = img->Width2; 935 GLint height = img->Height2; 936 GLint i0, j0, i1, j1; 937 GLint i0border, j0border, i1border, j1border; 938 GLfloat u, v; 939 940 u = s * width; 941 if (tObj->WrapS==GL_REPEAT) { 942 i0 = ((GLint) floor(u - 0.5F)) % width; 943 i1 = (i0 + 1) & (width-1); 944 i0border = i1border = 0; 945 } 946 else { 947 i0 = (GLint) floor(u - 0.5F); 948 i1 = i0 + 1; 949 i0border = (i0<0) | (i0>=width); 950 i1border = (i1<0) | (i1>=width); 951 } 952 953 v = t * height; 954 if (tObj->WrapT==GL_REPEAT) { 955 j0 = ((GLint) floor(v - 0.5F)) % height; 956 j1 = (j0 + 1) & (height-1); 957 j0border = j1border = 0; 958 } 959 else { 960 j0 = (GLint) floor(v - 0.5F ); 961 j1 = j0 + 1; 962 j0border = (j0<0) | (j0>=height); 963 j1border = (j1<0) | (j1>=height); 964 } 965 966 if (img->Border) { 967 i0 += img->Border; 968 i1 += img->Border; 969 j0 += img->Border; 970 j1 += img->Border; 971 i0border = i1border = 0; 972 j0border = j1border = 0; 973 } 974 else { 975 i0 &= (width-1); 976 j0 &= (height-1); 977 } 978 979 { 980 GLfloat a = frac(u - 0.5F); 981 GLfloat b = frac(v - 0.5F); 982 983 GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * 256.0F); 984 GLint w10 = (GLint) ( a *(1.0F-b) * 256.0F); 985 GLint w01 = (GLint) ((1.0F-a)* b * 256.0F); 986 GLint w11 = (GLint) ( a * b * 256.0F); 987 988 GLubyte red00, green00, blue00, alpha00; 989 GLubyte red10, green10, blue10, alpha10; 990 GLubyte red01, green01, blue01, alpha01; 991 GLubyte red11, green11, blue11, alpha11; 992 993 if (i0border | j0border) { 994 red00 = tObj->BorderColor[0]; 995 green00 = tObj->BorderColor[1]; 996 blue00 = tObj->BorderColor[2]; 997 alpha00 = tObj->BorderColor[3]; 998 } 999 else { 1000 get_2d_texel( tObj, img, i0, j0, &red00, &green00, &blue00, &alpha00); 1001 } 1002 if (i1border | j0border) { 1003 red10 = tObj->BorderColor[0]; 1004 green10 = tObj->BorderColor[1]; 1005 blue10 = tObj->BorderColor[2]; 1006 alpha10 = tObj->BorderColor[3]; 1007 } 1008 else { 1009 get_2d_texel( tObj, img, i1, j0, &red10, &green10, &blue10, &alpha10); 1010 } 1011 if (i0border | j1border) { 1012 red01 = tObj->BorderColor[0]; 1013 green01 = tObj->BorderColor[1]; 1014 blue01 = tObj->BorderColor[2]; 1015 alpha01 = tObj->BorderColor[3]; 1016 } 1017 else { 1018 get_2d_texel( tObj, img, i0, j1, &red01, &green01, &blue01, &alpha01); 1019 } 1020 if (i1border | j1border) { 1021 red11 = tObj->BorderColor[0]; 1022 green11 = tObj->BorderColor[1]; 1023 blue11 = tObj->BorderColor[2]; 1024 alpha11 = tObj->BorderColor[3]; 1025 } 1026 else { 1027 get_2d_texel( tObj, img, i1, j1, &red11, &green11, &blue11, &alpha11); 1028 } 1029 1030 *red = (w00*red00 + w10*red10 + w01*red01 + w11*red11 ) >> 8; 1031 *green = (w00*green00 + w10*green10 + w01*green01 + w11*green11) >> 8; 1032 *blue = (w00*blue00 + w10*blue10 + w01*blue01 + w11*blue11 ) >> 8; 1033 *alpha = (w00*alpha00 + w10*alpha10 + w01*alpha01 + w11*alpha11) >> 8; 1034 } 1035 } 1036 1037 1038 1039 static void 1040 sample_2d_nearest_mipmap_nearest( const struct gl_texture_object *tObj, 1041 GLfloat s, GLfloat t, GLfloat lambda, 1042 GLubyte *red, GLubyte *green, 1043 GLubyte *blue, GLubyte *alpha ) 1044 { 1045 GLint level; 1046 if (lambda<=0.5F) { 1047 level = 0; 1048 } 1049 else { 1050 GLint max = tObj->Image[0]->MaxLog2; 1051 level = (GLint) (lambda + 0.499999F); 1052 if (level>max) { 1053 level = max; 1054 } 1055 } 1056 sample_2d_nearest( tObj, tObj->Image[level], 1057 s, t, red, green, blue, alpha ); 1058 } 1059 1060 1061 1062 static void 1063 sample_2d_linear_mipmap_nearest( const struct gl_texture_object *tObj, 1064 GLfloat s, GLfloat t, GLfloat lambda, 1065 GLubyte *red, GLubyte *green, 1066 GLubyte *blue, GLubyte *alpha ) 1067 { 1068 GLint level; 1069 if (lambda<=0.5F) { 1070 level = 0; 1071 } 1072 else { 1073 GLint max = tObj->Image[0]->MaxLog2; 1074 level = (GLint) (lambda + 0.499999F); 1075 if (level>max) { 1076 level = max; 1077 } 1078 } 1079 sample_2d_linear( tObj, tObj->Image[level], 1080 s, t, red, green, blue, alpha ); 1081 } 1082 1083 1084 1085 static void 1086 sample_2d_nearest_mipmap_linear( const struct gl_texture_object *tObj, 1087 GLfloat s, GLfloat t, GLfloat lambda, 1088 GLubyte *red, GLubyte *green, 1089 GLubyte *blue, GLubyte *alpha ) 1090 { 1091 GLint max = tObj->Image[0]->MaxLog2; 1092 1093 if (lambda>=max) { 1094 sample_2d_nearest( tObj, tObj->Image[max], 1095 s, t, red, green, blue, alpha ); 1096 } 1097 else { 1098 GLubyte red0, green0, blue0, alpha0; 1099 GLubyte red1, green1, blue1, alpha1; 1100 GLfloat f = frac(lambda); 1101 GLint level = (GLint) (lambda + 1.0F); 1102 level = CLAMP( level, 1, max ); 1103 sample_2d_nearest( tObj, tObj->Image[level-1], s, t, 1104 &red0, &green0, &blue0, &alpha0 ); 1105 sample_2d_nearest( tObj, tObj->Image[level], s, t, 1106 &red1, &green1, &blue1, &alpha1 ); 1107 *red = (1.0F-f)*red0 + f*red1; 1108 *green = (1.0F-f)*green0 + f*green1; 1109 *blue = (1.0F-f)*blue0 + f*blue1; 1110 *alpha = (1.0F-f)*alpha0 + f*alpha1; 1111 } 1112 } 1113 1114 1115 1116 static void 1117 sample_2d_linear_mipmap_linear( const struct gl_texture_object *tObj, 1118 GLfloat s, GLfloat t, GLfloat lambda, 1119 GLubyte *red, GLubyte *green, 1120 GLubyte *blue, GLubyte *alpha ) 1121 { 1122 GLint max = tObj->Image[0]->MaxLog2; 1123 1124 if (lambda>=max) { 1125 sample_2d_linear( tObj, tObj->Image[max], 1126 s, t, red, green, blue, alpha ); 1127 } 1128 else { 1129 GLubyte red0, green0, blue0, alpha0; 1130 GLubyte red1, green1, blue1, alpha1; 1131 GLfloat f = frac(lambda); 1132 GLint level = (GLint) (lambda + 1.0F); 1133 level = CLAMP( level, 1, max ); 1134 sample_2d_linear( tObj, tObj->Image[level-1], s, t, 1135 &red0, &green0, &blue0, &alpha0 ); 1136 sample_2d_linear( tObj, tObj->Image[level], s, t, 1137 &red1, &green1, &blue1, &alpha1 ); 1138 *red = (1.0F-f)*red0 + f*red1; 1139 *green = (1.0F-f)*green0 + f*green1; 1140 *blue = (1.0F-f)*blue0 + f*blue1; 1141 *alpha = (1.0F-f)*alpha0 + f*alpha1; 1142 } 1143 } 1144 1145 1146 1147 static void sample_nearest_2d( const struct gl_texture_object *tObj, GLuint n, 1148 const GLfloat s[], const GLfloat t[], 1149 const GLfloat u[], const GLfloat lambda[], 1150 GLubyte red[], GLubyte green[], GLubyte blue[], 1151 GLubyte alpha[] ) 1152 { 1153 GLuint i; 1154 for (i=0;i<n;i++) { 1155 sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i], 1156 &red[i], &green[i], &blue[i], &alpha[i]); 1157 } 1158 } 1159 1160 1161 1162 static void sample_linear_2d( const struct gl_texture_object *tObj, GLuint n, 1163 const GLfloat s[], const GLfloat t[], 1164 const GLfloat u[], const GLfloat lambda[], 1165 GLubyte red[], GLubyte green[], GLubyte blue[], 1166 GLubyte alpha[] ) 1167 { 1168 GLuint i; 1169 for (i=0;i<n;i++) { 1170 sample_2d_linear( tObj, tObj->Image[0], s[i], t[i], 1171 &red[i], &green[i], &blue[i], &alpha[i]); 1172 } 1173 } 1174 1175 1176 /* 1177 * Given an (s,t) texture coordinate and lambda (level of detail) value, 1178 * return a texture sample. 1179 */ 1180 static void sample_lambda_2d( const struct gl_texture_object *tObj, 1181 GLuint n, 1182 const GLfloat s[], const GLfloat t[], 1183 const GLfloat u[], const GLfloat lambda[], 1184 GLubyte red[], GLubyte green[], GLubyte blue[], 1185 GLubyte alpha[] ) 1186 { 1187 GLuint i; 1188 for (i=0;i<n;i++) { 1189 if (lambda[i] > tObj->MinMagThresh) { 1190 /* minification */ 1191 switch (tObj->MinFilter) { 1192 case GL_NEAREST: 1193 sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i], 1194 &red[i], &green[i], &blue[i], &alpha[i] ); 1195 break; 1196 case GL_LINEAR: 1197 sample_2d_linear( tObj, tObj->Image[0], s[i], t[i], 1198 &red[i], &green[i], &blue[i], &alpha[i] ); 1199 break; 1200 case GL_NEAREST_MIPMAP_NEAREST: 1201 sample_2d_nearest_mipmap_nearest( tObj, s[i], t[i], lambda[i], 1202 &red[i], &green[i], &blue[i], &alpha[i] ); 1203 break; 1204 case GL_LINEAR_MIPMAP_NEAREST: 1205 sample_2d_linear_mipmap_nearest( tObj, s[i], t[i], lambda[i], 1206 &red[i], &green[i], &blue[i], &alpha[i] ); 1207 break; 1208 case GL_NEAREST_MIPMAP_LINEAR: 1209 sample_2d_nearest_mipmap_linear( tObj, s[i], t[i], lambda[i], 1210 &red[i], &green[i], &blue[i], &alpha[i] ); 1211 break; 1212 case GL_LINEAR_MIPMAP_LINEAR: 1213 sample_2d_linear_mipmap_linear( tObj, s[i], t[i], lambda[i], 1214 &red[i], &green[i], &blue[i], &alpha[i] ); 1215 break; 1216 default: 1217 gl_problem(NULL, "Bad min filter in sample_2d_texture"); 1218 return; 1219 } 1220 } 1221 else { 1222 /* magnification */ 1223 switch (tObj->MagFilter) { 1224 case GL_NEAREST: 1225 sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i], 1226 &red[i], &green[i], &blue[i], &alpha[i] ); 1227 break; 1228 case GL_LINEAR: 1229 sample_2d_linear( tObj, tObj->Image[0], s[i], t[i], 1230 &red[i], &green[i], &blue[i], &alpha[i] ); 1231 break; 1232 default: 1233 gl_problem(NULL, "Bad mag filter in sample_2d_texture"); 1234 } 1235 } 1236 } 1237 } 1238 1239 1240 /* 1241 * Optimized 2-D texture sampling: 1242 * S and T wrap mode == GL_REPEAT 1243 * No border 1244 * Format = GL_RGB 1245 */ 1246 static void opt_sample_rgb_2d( const struct gl_texture_object *tObj, 1247 GLuint n, const GLfloat s[], const GLfloat t[], 1248 const GLfloat u[], const GLfloat lamda[], 1249 GLubyte red[], GLubyte green[], 1250 GLubyte blue[], GLubyte alpha[] ) 1251 { 1252 const struct gl_texture_image *img = tObj->Image[0]; 1253 GLfloat width = img->Width, height = img->Height; 1254 GLint colMask = img->Width-1, rowMask = img->Height-1; 1255 GLint shift = img->WidthLog2; 1256 GLuint k; 1257 1258 ASSERT(tObj->WrapS==GL_REPEAT); 1259 ASSERT(tObj->WrapT==GL_REPEAT); 1260 ASSERT(img->Border==0); 1261 ASSERT(img->Format==GL_RGB); 1262 1263 for (k=0;k<n;k++) { 1264 GLint i = (GLint) (s[k] * width) & colMask; 1265 GLint j = (GLint) (t[k] * height) & rowMask; 1266 GLint pos = (j << shift) | i; 1267 GLubyte *texel = img->Data + pos + pos + pos; /* pos*3 */ 1268 red[k] = texel[0]; 1269 green[k] = texel[1]; 1270 blue[k] = texel[2]; 1271 } 1272 } 1273 1274 1275 /* 1276 * Optimized 2-D texture sampling: 1277 * S and T wrap mode == GL_REPEAT 1278 * No border 1279 * Format = GL_RGBA 1280 */ 1281 static void opt_sample_rgba_2d( const struct gl_texture_object *tObj, 1282 GLuint n, const GLfloat s[], const GLfloat t[], 1283 const GLfloat u[], const GLfloat lamda[], 1284 GLubyte red[], GLubyte green[], 1285 GLubyte blue[], GLubyte alpha[] ) 1286 { 1287 const struct gl_texture_image *img = tObj->Image[0]; 1288 GLfloat width = img->Width, height = img->Height; 1289 GLint colMask = img->Width-1, rowMask = img->Height-1; 1290 GLint shift = img->WidthLog2; 1291 GLuint k; 1292 1293 ASSERT(tObj->WrapS==GL_REPEAT); 1294 ASSERT(tObj->WrapT==GL_REPEAT); 1295 ASSERT(img->Border==0); 1296 ASSERT(img->Format==GL_RGBA); 1297 1298 for (k=0;k<n;k++) { 1299 GLint i = (GLint) (s[k] * width) & colMask; 1300 GLint j = (GLint) (t[k] * height) & rowMask; 1301 GLint pos = (j << shift) | i; 1302 GLubyte *texel = img->Data + (pos << 2); /* pos*4 */ 1303 red[k] = texel[0]; 1304 green[k] = texel[1]; 1305 blue[k] = texel[2]; 1306 alpha[k] = texel[3]; 1307 } 1308 } 1309 1310 1311 /**********************************************************************/ 1312 /* Texture Sampling Setup */ 1313 /**********************************************************************/ 1314 1315 1316 /* 1317 * Setup the texture sampling function for this texture object. 1318 */ 1319 void gl_set_texture_sampler( struct gl_texture_object *t ) 1320 { 1321 if (!t->Complete) { 1322 t->SampleFunc = NULL; 1323 } 1324 else { 1325 GLboolean needLambda = (t->MinFilter != t->MagFilter); 1326 1327 if (needLambda) { 1328 /* Compute min/mag filter threshold */ 1329 if (t->MagFilter==GL_LINEAR 1330 && (t->MinFilter==GL_NEAREST_MIPMAP_NEAREST || 1331 t->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) { 1332 t->MinMagThresh = 0.5F; 1333 } 1334 else { 1335 t->MinMagThresh = 0.0F; 1336 } 1337 } 1338 1339 switch (t->Dimensions) { 1340 case 1: 1341 if (needLambda) { 1342 t->SampleFunc = sample_lambda_1d; 1343 } 1344 else if (t->MinFilter==GL_LINEAR) { 1345 t->SampleFunc = sample_linear_1d; 1346 } 1347 else { 1348 ASSERT(t->MinFilter==GL_NEAREST); 1349 t->SampleFunc = sample_nearest_1d; 1350 } 1351 break; 1352 case 2: 1353 if (needLambda) { 1354 t->SampleFunc = sample_lambda_2d; 1355 } 1356 else if (t->MinFilter==GL_LINEAR) { 1357 t->SampleFunc = sample_linear_2d; 1358 } 1359 else { 1360 ASSERT(t->MinFilter==GL_NEAREST); 1361 if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT 1362 && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGB) { 1363 t->SampleFunc = opt_sample_rgb_2d; 1364 } 1365 else if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT 1366 && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGBA) { 1367 t->SampleFunc = opt_sample_rgba_2d; 1368 } 1369 else 1370 t->SampleFunc = sample_nearest_2d; 1371 } 1372 break; 1373 default: 1374 gl_problem(NULL, "invalid dimensions in gl_set_texture_sampler"); 1375 } 1376 } 1377 } 1378 1379 1380 1381 /**********************************************************************/ 1382 /* Texture Application */ 1383 /**********************************************************************/ 1384 1385 1386 /* 1387 * Combine incoming fragment color with texel color to produce output color. 1388 * Input: n - number of fragments 1389 * format - base internal texture format 1390 * env_mode - texture environment mode 1391 * Rt, Gt, Bt, At - array of texel colors 1392 * InOut: red, green, blue, alpha - incoming fragment colors modified 1393 * by texel colors according to the 1394 * texture environment mode. 1395 */ 1396 static void apply_texture( GLcontext *ctx, 1397 GLuint n, GLint format, GLenum env_mode, 1398 GLubyte red[], GLubyte green[], GLubyte blue[], GLubyte alpha[], 1399 GLubyte Rt[], GLubyte Gt[], GLubyte Bt[], GLubyte At[] ) 1400 { 1401 GLuint i; 1402 GLint Rc, Gc, Bc, Ac; 1403 1404 if (!ctx->Visual->EightBitColor) { 1405 /* This is a hack! Rescale input colors from [0,scale] to [0,255]. */ 1406 GLfloat rscale = 255.0 * ctx->Visual->InvRedScale; 1407 GLfloat gscale = 255.0 * ctx->Visual->InvGreenScale; 1408 GLfloat bscale = 255.0 * ctx->Visual->InvBlueScale; 1409 GLfloat ascale = 255.0 * ctx->Visual->InvAlphaScale; 1410 for (i=0;i<n;i++) { 1411 red[i] = (GLint) (red[i] * rscale); 1412 green[i] = (GLint) (green[i] * gscale); 1413 blue[i] = (GLint) (blue[i] * bscale); 1414 alpha[i] = (GLint) (alpha[i] * ascale); 1415 } 1416 } 1417 1418 /* 1419 * Use (A*(B+1)) >> 8 as a fast approximation of (A*B)/255 for A 1420 * and B in [0,255] 1421 */ 1422 #define PROD(A,B) (((GLint)(A) * ((GLint)(B)+1)) >> 8) 1423 1424 if (format==GL_COLOR_INDEX) { 1425 format = GL_RGBA; /* XXXX a hack! */ 1426 } 1427 1428 switch (env_mode) { 1429 case GL_REPLACE: 1430 switch (format) { 1431 case GL_ALPHA: 1432 for (i=0;i<n;i++) { 1433 /* Cv = Cf */ 1434 /* Av = At */ 1435 alpha[i] = At[i]; 1436 } 1437 break; 1438 case GL_LUMINANCE: 1439 for (i=0;i<n;i++) { 1440 /* Cv = Lt */ 1441 GLint Lt = Rt[i]; 1442 red[i] = green[i] = blue[i] = Lt; 1443 /* Av = Af */ 1444 } 1445 break; 1446 case GL_LUMINANCE_ALPHA: 1447 for (i=0;i<n;i++) { 1448 GLint Lt = Rt[i]; 1449 /* Cv = Lt */ 1450 red[i] = green[i] = blue[i] = Lt; 1451 /* Av = At */ 1452 alpha[i] = At[i]; 1453 } 1454 break; 1455 case GL_INTENSITY: 1456 for (i=0;i<n;i++) { 1457 /* Cv = It */ 1458 GLint It = Rt[i]; 1459 red[i] = green[i] = blue[i] = It; 1460 /* Av = It */ 1461 alpha[i] = It; 1462 } 1463 break; 1464 case GL_RGB: 1465 for (i=0;i<n;i++) { 1466 /* Cv = Ct */ 1467 red[i] = Rt[i]; 1468 green[i] = Gt[i]; 1469 blue[i] = Bt[i]; 1470 /* Av = Af */ 1471 } 1472 break; 1473 case GL_RGBA: 1474 for (i=0;i<n;i++) { 1475 /* Cv = Ct */ 1476 red[i] = Rt[i]; 1477 green[i] = Gt[i]; 1478 blue[i] = Bt[i]; 1479 /* Av = At */ 1480 alpha[i] = At[i]; 1481 } 1482 break; 1483 default: 1484 gl_problem(ctx, "Bad format in apply_texture"); 1485 return; 1486 } 1487 break; 1488 1489 case GL_MODULATE: 1490 switch (format) { 1491 case GL_ALPHA: 1492 for (i=0;i<n;i++) { 1493 /* Cv = Cf */ 1494 /* Av = AfAt */ 1495 alpha[i] = PROD( alpha[i], At[i] ); 1496 } 1497 break; 1498 case GL_LUMINANCE: 1499 for (i=0;i<n;i++) { 1500 /* Cv = LtCf */ 1501 GLint Lt = Rt[i]; 1502 red[i] = PROD( red[i], Lt ); 1503 green[i] = PROD( green[i], Lt ); 1504 blue[i] = PROD( blue[i], Lt ); 1505 /* Av = Af */ 1506 } 1507 break; 1508 case GL_LUMINANCE_ALPHA: 1509 for (i=0;i<n;i++) { 1510 /* Cv = CfLt */ 1511 GLint Lt = Rt[i]; 1512 red[i] = PROD( red[i], Lt ); 1513 green[i] = PROD( green[i], Lt ); 1514 blue[i] = PROD( blue[i], Lt ); 1515 /* Av = AfAt */ 1516 alpha[i] = PROD( alpha[i], At[i] ); 1517 } 1518 break; 1519 case GL_INTENSITY: 1520 for (i=0;i<n;i++) { 1521 /* Cv = CfIt */ 1522 GLint It = Rt[i]; 1523 red[i] = PROD( red[i], It ); 1524 green[i] = PROD( green[i], It ); 1525 blue[i] = PROD( blue[i], It ); 1526 /* Av = AfIt */ 1527 alpha[i] = PROD( alpha[i], It ); 1528 } 1529 break; 1530 case GL_RGB: 1531 for (i=0;i<n;i++) { 1532 /* Cv = CfCt */ 1533 red[i] = PROD( red[i], Rt[i] ); 1534 green[i] = PROD( green[i], Gt[i] ); 1535 blue[i] = PROD( blue[i], Bt[i] ); 1536 /* Av = Af */ 1537 } 1538 break; 1539 case GL_RGBA: 1540 for (i=0;i<n;i++) { 1541 /* Cv = CfCt */ 1542 red[i] = PROD( red[i], Rt[i] ); 1543 green[i] = PROD( green[i], Gt[i] ); 1544 blue[i] = PROD( blue[i], Bt[i] ); 1545 /* Av = AfAt */ 1546 alpha[i] = PROD( alpha[i], At[i] ); 1547 } 1548 break; 1549 default: 1550 gl_problem(ctx, "Bad format (2) in apply_texture"); 1551 return; 1552 } 1553 break; 1554 1555 case GL_DECAL: 1556 switch (format) { 1557 case GL_ALPHA: 1558 case GL_LUMINANCE: 1559 case GL_LUMINANCE_ALPHA: 1560 case GL_INTENSITY: 1561 /* undefined */ 1562 break; 1563 case GL_RGB: 1564 for (i=0;i<n;i++) { 1565 /* Cv = Ct */ 1566 red[i] = Rt[i]; 1567 green[i] = Gt[i]; 1568 blue[i] = Bt[i]; 1569 /* Av = Af */ 1570 } 1571 break; 1572 case GL_RGBA: 1573 for (i=0;i<n;i++) { 1574 /* Cv = Cf(1-At) + CtAt */ 1575 GLint t = At[i], s = 255 - t; 1576 red[i] = PROD(red[i], s) + PROD(Rt[i],t); 1577 green[i] = PROD(green[i],s) + PROD(Gt[i],t); 1578 blue[i] = PROD(blue[i], s) + PROD(Bt[i],t); 1579 /* Av = Af */ 1580 } 1581 break; 1582 default: 1583 gl_problem(ctx, "Bad format (3) in apply_texture"); 1584 return; 1585 } 1586 break; 1587 1588 case GL_BLEND: 1589 Rc = (GLint) (ctx->Texture.EnvColor[0] * 255.0F); 1590 Gc = (GLint) (ctx->Texture.EnvColor[1] * 255.0F); 1591 Bc = (GLint) (ctx->Texture.EnvColor[2] * 255.0F); 1592 Ac = (GLint) (ctx->Texture.EnvColor[3] * 255.0F); 1593 switch (format) { 1594 case GL_ALPHA: 1595 for (i=0;i<n;i++) { 1596 /* Cv = Cf */ 1597 /* Av = AfAt */ 1598 alpha[i] = PROD(alpha[i], At[i]); 1599 } 1600 break; 1601 case GL_LUMINANCE: 1602 for (i=0;i<n;i++) { 1603 /* Cv = Cf(1-Lt) + CcLt */ 1604 GLint Lt = Rt[i], s = 255 - Lt; 1605 red[i] = PROD(red[i], s) + PROD(Rc, Lt); 1606 green[i] = PROD(green[i],s) + PROD(Gc,Lt); 1607 blue[i] = PROD(blue[i], s) + PROD(Bc, Lt); 1608 /* Av = Af */ 1609 } 1610 break; 1611 case GL_LUMINANCE_ALPHA: 1612 for (i=0;i<n;i++) { 1613 /* Cv = Cf(1-Lt) + CcLt */ 1614 GLint Lt = Rt[i], s = 255 - Lt; 1615 red[i] = PROD(red[i], s) + PROD(Rc, Lt); 1616 green[i] = PROD(green[i],s) + PROD(Gc,Lt); 1617 blue[i] = PROD(blue[i], s) + PROD(Bc, Lt); 1618 /* Av = AfAt */ 1619 alpha[i] = PROD(alpha[i],At[i]); 1620 } 1621 break; 1622 case GL_INTENSITY: 1623 for (i=0;i<n;i++) { 1624 /* Cv = Cf(1-It) + CcLt */ 1625 GLint It = Rt[i], s = 255 - It; 1626 red[i] = PROD(red[i], s) + PROD(Rc,It); 1627 green[i] = PROD(green[i],s) + PROD(Gc,It); 1628 blue[i] = PROD(blue[i], s) + PROD(Bc,It); 1629 /* Av = Af(1-It) + Ac*It */ 1630 alpha[i] = PROD(alpha[i],s) + PROD(Ac,It); 1631 } 1632 break; 1633 case GL_RGB: 1634 for (i=0;i<n;i++) { 1635 /* Cv = Cf(1-Ct) + CcCt */ 1636 red[i] = PROD(red[i], (255-Rt[i])) + PROD(Rc,Rt[i]); 1637 green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]); 1638 blue[i] = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]); 1639 /* Av = Af */ 1640 } 1641 break; 1642 case GL_RGBA: 1643 for (i=0;i<n;i++) { 1644 /* Cv = Cf(1-Ct) + CcCt */ 1645 red[i] = PROD(red[i], (255-Rt[i])) + PROD(Rc,Rt[i]); 1646 green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]); 1647 blue[i] = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]); 1648 /* Av = AfAt */ 1649 alpha[i] = PROD(alpha[i],At[i]); 1650 } 1651 break; 1652 } 1653 break; 1654 1655 default: 1656 gl_problem(ctx, "Bad env mode in apply_texture"); 1657 return; 1658 } 1659 #undef PROD 1660 1661 if (!ctx->Visual->EightBitColor) { 1662 /* This is a hack! Rescale input colors from [0,255] to [0,scale]. */ 1663 GLfloat rscale = ctx->Visual->RedScale * (1.0F/ 255.0F); 1664 GLfloat gscale = ctx->Visual->GreenScale * (1.0F/ 255.0F); 1665 GLfloat bscale = ctx->Visual->BlueScale * (1.0F/ 255.0F); 1666 GLfloat ascale = ctx->Visual->AlphaScale * (1.0F/ 255.0F); 1667 for (i=0;i<n;i++) { 1668 red[i] = (GLint) (red[i] * rscale); 1669 green[i] = (GLint) (green[i] * gscale); 1670 blue[i] = (GLint) (blue[i] * bscale); 1671 alpha[i] = (GLint) (alpha[i] * ascale); 1672 } 1673 } 1674 } 1675 1676 1677 1678 void gl_texture_pixels( GLcontext *ctx, GLuint n, 1679 const GLfloat s[], const GLfloat t[], 1680 const GLfloat r[], const GLfloat lambda[], 1681 GLubyte red[], GLubyte green[], 1682 GLubyte blue[], GLubyte alpha[] ) 1683 { 1684 GLubyte tred[PB_SIZE]; 1685 GLubyte tgreen[PB_SIZE]; 1686 GLubyte tblue[PB_SIZE]; 1687 GLubyte talpha[PB_SIZE]; 1688 1689 if (!ctx->Texture.Current || !ctx->Texture.Current->SampleFunc) 1690 return; 1691 1692 /* Sample the texture. */ 1693 (*ctx->Texture.Current->SampleFunc)( ctx->Texture.Current, n, 1694 s, t, r, lambda, 1695 tred, tgreen, tblue, talpha ); 1696 1697 apply_texture( ctx, n, 1698 ctx->Texture.Current->Image[0]->Format, 1699 ctx->Texture.EnvMode, 1700 red, green, blue, alpha, 1701 tred, tgreen, tblue, talpha ); 1702 } 1703