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 */
gl_texgen(GLcontext * ctx,GLint n,GLfloat obj[][4],GLfloat eye[][4],GLfloat normal[][3],GLfloat texcoord[][4])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 */
palette_sample(const struct gl_texture_object * tObj,GLubyte index,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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 */
get_1d_texel(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLint i,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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 */
sample_1d_nearest(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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 */
sample_1d_linear(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_1d_nearest_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_1d_linear_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_1d_nearest_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_1d_linear_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_nearest_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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
sample_linear_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
sample_lambda_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
get_2d_texel(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLint i,GLint j,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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 */
sample_2d_nearest(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLfloat t,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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 */
sample_2d_linear(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLfloat t,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_2d_nearest_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_2d_linear_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_2d_nearest_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_2d_linear_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)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
sample_nearest_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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
sample_linear_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
sample_lambda_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
opt_sample_rgb_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lamda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
opt_sample_rgba_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lamda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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 */
gl_set_texture_sampler(struct gl_texture_object * t)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 */
apply_texture(GLcontext * ctx,GLuint n,GLint format,GLenum env_mode,GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[],GLubyte Rt[],GLubyte Gt[],GLubyte Bt[],GLubyte At[])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
gl_texture_pixels(GLcontext * ctx,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat r[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])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