07e005b1502301da4a6087ef30a7a9bb9ffc346c
[mesa.git] / src / mesa / swrast / s_texture.c
1 /* $Id: s_texture.c,v 1.52 2002/02/16 23:44:46 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #include "glheader.h"
29 #include "context.h"
30 #include "colormac.h"
31 #include "macros.h"
32 #include "mmath.h"
33 #include "mem.h"
34 #include "texformat.h"
35 #include "teximage.h"
36
37 #include "s_context.h"
38 #include "s_texture.h"
39
40
41 /*
42 * These values are used in the fixed-point arithmetic used
43 * for linear filtering.
44 */
45 #define WEIGHT_SCALE 65536.0F
46 #define WEIGHT_SHIFT 16
47
48
49 /*
50 * Used to compute texel locations for linear sampling.
51 * Input:
52 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER_ARB
53 * S = texcoord in [0,1]
54 * SIZE = width (or height or depth) of texture
55 * Output:
56 * U = texcoord in [0, width]
57 * I0, I1 = two nearest texel indexes
58 */
59 #define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
60 { \
61 if (wrapMode == GL_REPEAT) { \
62 U = S * SIZE - 0.5F; \
63 I0 = IFLOOR(U) & (SIZE - 1); \
64 I1 = (I0 + 1) & (SIZE - 1); \
65 } \
66 else if (wrapMode == GL_CLAMP_TO_EDGE) { \
67 if (S <= 0.0F) \
68 U = 0.0F; \
69 else if (S >= 1.0F) \
70 U = (GLfloat) SIZE; \
71 else \
72 U = S * SIZE; \
73 U -= 0.5F; \
74 I0 = IFLOOR(U); \
75 I1 = I0 + 1; \
76 if (I0 < 0) \
77 I0 = 0; \
78 if (I1 >= (GLint) SIZE) \
79 I1 = SIZE - 1; \
80 } \
81 else if (wrapMode == GL_CLAMP_TO_BORDER_ARB) { \
82 const GLfloat min = -1.0F / (2.0F * SIZE); \
83 const GLfloat max = 1.0F - min; \
84 if (S <= min) \
85 U = min * SIZE; \
86 else if (S >= max) \
87 U = max * SIZE; \
88 else \
89 U = S * SIZE; \
90 U -= 0.5F; \
91 I0 = IFLOOR(U); \
92 I1 = I0 + 1; \
93 } \
94 else if (wrapMode == GL_MIRRORED_REPEAT_ARB) { \
95 const GLint flr = IFLOOR(S); \
96 if (flr & 1) \
97 U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
98 else \
99 U = S - (GLfloat) flr; /* flr is even */ \
100 I0 = IFLOOR(U); \
101 I1 = I0 + 1; \
102 if (I0 < 0) \
103 I0 = 0; \
104 if (I1 >= (GLint) SIZE) \
105 I1 = SIZE - 1; \
106 } \
107 else { \
108 ASSERT(wrapMode == GL_CLAMP); \
109 if (S <= 0.0F) \
110 U = 0.0F; \
111 else if (S >= 1.0F) \
112 U = (GLfloat) SIZE; \
113 else \
114 U = S * SIZE; \
115 U -= 0.5F; \
116 I0 = IFLOOR(U); \
117 I1 = I0 + 1; \
118 } \
119 }
120
121
122 /*
123 * Used to compute texel location for nearest sampling.
124 */
125 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
126 { \
127 if (wrapMode == GL_REPEAT) { \
128 /* s limited to [0,1) */ \
129 /* i limited to [0,size-1] */ \
130 I = IFLOOR(S * SIZE); \
131 I &= (SIZE - 1); \
132 } \
133 else if (wrapMode == GL_CLAMP_TO_EDGE) { \
134 /* s limited to [min,max] */ \
135 /* i limited to [0, size-1] */ \
136 const GLfloat min = 1.0F / (2.0F * SIZE); \
137 const GLfloat max = 1.0F - min; \
138 if (S < min) \
139 I = 0; \
140 else if (S > max) \
141 I = SIZE - 1; \
142 else \
143 I = IFLOOR(S * SIZE); \
144 } \
145 else if (wrapMode == GL_CLAMP_TO_BORDER_ARB) { \
146 /* s limited to [min,max] */ \
147 /* i limited to [-1, size] */ \
148 const GLfloat min = -1.0F / (2.0F * SIZE); \
149 const GLfloat max = 1.0F - min; \
150 if (S <= min) \
151 I = -1; \
152 else if (S >= max) \
153 I = SIZE; \
154 else \
155 I = IFLOOR(S * SIZE); \
156 } \
157 else if (wrapMode == GL_MIRRORED_REPEAT_ARB) { \
158 const GLfloat min = 1.0F / (2.0F * SIZE); \
159 const GLfloat max = 1.0F - min; \
160 const GLint flr = IFLOOR(S); \
161 GLfloat u; \
162 if (flr & 1) \
163 u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
164 else \
165 u = S - (GLfloat) flr; /* flr is even */ \
166 if (u < min) \
167 I = 0; \
168 else if (u > max) \
169 I = SIZE - 1; \
170 else \
171 I = IFLOOR(u * SIZE); \
172 } \
173 else { \
174 ASSERT(wrapMode == GL_CLAMP); \
175 /* s limited to [0,1] */ \
176 /* i limited to [0,size-1] */ \
177 if (S <= 0.0F) \
178 I = 0; \
179 else if (S >= 1.0F) \
180 I = SIZE - 1; \
181 else \
182 I = IFLOOR(S * SIZE); \
183 } \
184 }
185
186
187 /*
188 * Compute linear mipmap levels for given lambda.
189 */
190 #define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level) \
191 { \
192 if (lambda < 0.0F) \
193 lambda = 0.0F; \
194 else if (lambda > tObj->_MaxLambda) \
195 lambda = tObj->_MaxLambda; \
196 level = (GLint) (tObj->BaseLevel + lambda); \
197 }
198
199
200 /*
201 * Compute nearest mipmap level for given lambda.
202 */
203 #define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \
204 { \
205 if (lambda <= 0.5F) \
206 lambda = 0.0F; \
207 else if (lambda > tObj->_MaxLambda + 0.4999F) \
208 lambda = tObj->_MaxLambda + 0.4999F; \
209 level = (GLint) (tObj->BaseLevel + lambda + 0.5F); \
210 if (level > tObj->_MaxLevel) \
211 level = tObj->_MaxLevel; \
212 }
213
214
215
216 /*
217 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
218 * see 1-pixel bands of improperly weighted linear-sampled texels. The
219 * tests/texwrap.c demo is a good test.
220 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
221 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
222 */
223 #define FRAC(f) ((f) - IFLOOR(f))
224
225
226
227 /*
228 * Bitflags for texture border color sampling.
229 */
230 #define I0BIT 1
231 #define I1BIT 2
232 #define J0BIT 4
233 #define J1BIT 8
234 #define K0BIT 16
235 #define K1BIT 32
236
237
238
239 /*
240 * Get texture palette entry.
241 */
242 static void
243 palette_sample(const GLcontext *ctx,
244 const struct gl_texture_object *tObj,
245 GLint index, GLchan rgba[4] )
246 {
247 const GLchan *palette;
248 GLenum format;
249
250 if (ctx->Texture.SharedPalette) {
251 ASSERT(!ctx->Texture.Palette.FloatTable);
252 palette = (const GLchan *) ctx->Texture.Palette.Table;
253 format = ctx->Texture.Palette.Format;
254 }
255 else {
256 ASSERT(!tObj->Palette.FloatTable);
257 palette = (const GLchan *) tObj->Palette.Table;
258 format = tObj->Palette.Format;
259 }
260
261 switch (format) {
262 case GL_ALPHA:
263 rgba[ACOMP] = palette[index];
264 return;
265 case GL_LUMINANCE:
266 case GL_INTENSITY:
267 rgba[RCOMP] = palette[index];
268 return;
269 case GL_LUMINANCE_ALPHA:
270 rgba[RCOMP] = palette[(index << 1) + 0];
271 rgba[ACOMP] = palette[(index << 1) + 1];
272 return;
273 case GL_RGB:
274 rgba[RCOMP] = palette[index * 3 + 0];
275 rgba[GCOMP] = palette[index * 3 + 1];
276 rgba[BCOMP] = palette[index * 3 + 2];
277 return;
278 case GL_RGBA:
279 rgba[RCOMP] = palette[(index << 2) + 0];
280 rgba[GCOMP] = palette[(index << 2) + 1];
281 rgba[BCOMP] = palette[(index << 2) + 2];
282 rgba[ACOMP] = palette[(index << 2) + 3];
283 return;
284 default:
285 _mesa_problem(ctx, "Bad palette format in palette_sample");
286 }
287 }
288
289
290
291 /**********************************************************************/
292 /* 1-D Texture Sampling Functions */
293 /**********************************************************************/
294
295 /*
296 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
297 */
298 static void
299 sample_1d_nearest(GLcontext *ctx,
300 const struct gl_texture_object *tObj,
301 const struct gl_texture_image *img,
302 const GLfloat texcoord[4], GLchan rgba[4])
303 {
304 const GLint width = img->Width2; /* without border, power of two */
305 GLint i;
306
307 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
308
309 /* skip over the border, if any */
310 i += img->Border;
311
312 if (i < 0 || i >= (GLint) img->Width) {
313 /* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
314 COPY_CHAN4(rgba, tObj->BorderColor);
315 }
316 else {
317 (*img->FetchTexel)(img, i, 0, 0, (GLvoid *) rgba);
318 if (img->Format == GL_COLOR_INDEX) {
319 palette_sample(ctx, tObj, rgba[0], rgba);
320 }
321 }
322 }
323
324
325
326 /*
327 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
328 */
329 static void
330 sample_1d_linear(GLcontext *ctx,
331 const struct gl_texture_object *tObj,
332 const struct gl_texture_image *img,
333 const GLfloat texcoord[4], GLchan rgba[4])
334 {
335 const GLint width = img->Width2;
336 GLint i0, i1;
337 GLfloat u;
338 GLuint useBorderColor;
339
340 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
341
342 useBorderColor = 0;
343 if (img->Border) {
344 i0 += img->Border;
345 i1 += img->Border;
346 }
347 else {
348 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
349 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
350 }
351
352 {
353 const GLfloat a = FRAC(u);
354
355 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
356 const GLfloat w0 = (1.0F-a);
357 const GLfloat w1 = a ;
358 #else /* CHAN_BITS == 8 */
359 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
360 const GLint w0 = IROUND_POS((1.0F - a) * WEIGHT_SCALE);
361 const GLint w1 = IROUND_POS( a * WEIGHT_SCALE);
362 #endif
363 GLchan t0[4], t1[4]; /* texels */
364
365 if (useBorderColor & I0BIT) {
366 COPY_CHAN4(t0, tObj->BorderColor);
367 }
368 else {
369 (*img->FetchTexel)(img, i0, 0, 0, (GLvoid *) t0);
370 if (img->Format == GL_COLOR_INDEX) {
371 palette_sample(ctx, tObj, t0[0], t0);
372 }
373 }
374 if (useBorderColor & I1BIT) {
375 COPY_CHAN4(t1, tObj->BorderColor);
376 }
377 else {
378 (*img->FetchTexel)(img, i1, 0, 0, (GLvoid *) t1);
379 if (img->Format == GL_COLOR_INDEX) {
380 palette_sample(ctx, tObj, t1[0], t1);
381 }
382 }
383
384 #if CHAN_TYPE == GL_FLOAT
385 rgba[0] = w0 * t0[0] + w1 * t1[0];
386 rgba[1] = w0 * t0[1] + w1 * t1[1];
387 rgba[2] = w0 * t0[2] + w1 * t1[2];
388 rgba[3] = w0 * t0[3] + w1 * t1[3];
389 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
390 rgba[0] = (GLchan) (w0 * t0[0] + w1 * t1[0] + 0.5);
391 rgba[1] = (GLchan) (w0 * t0[1] + w1 * t1[1] + 0.5);
392 rgba[2] = (GLchan) (w0 * t0[2] + w1 * t1[2] + 0.5);
393 rgba[3] = (GLchan) (w0 * t0[3] + w1 * t1[3] + 0.5);
394 #else /* CHAN_BITS == 8 */
395 rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT);
396 rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT);
397 rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT);
398 rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT);
399 #endif
400
401 }
402 }
403
404
405 static void
406 sample_1d_nearest_mipmap_nearest(GLcontext *ctx,
407 const struct gl_texture_object *tObj,
408 const GLfloat texcoord[4], GLfloat lambda,
409 GLchan rgba[4])
410 {
411 GLint level;
412 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
413 sample_1d_nearest(ctx, tObj, tObj->Image[level], texcoord, rgba);
414 }
415
416
417 static void
418 sample_1d_linear_mipmap_nearest(GLcontext *ctx,
419 const struct gl_texture_object *tObj,
420 const GLfloat texcoord[4], GLfloat lambda,
421 GLchan rgba[4])
422 {
423 GLint level;
424 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
425 sample_1d_linear(ctx, tObj, tObj->Image[level], texcoord, rgba);
426 }
427
428
429
430 /*
431 * This is really just needed in order to prevent warnings with some compilers.
432 */
433 #if CHAN_TYPE == GL_FLOAT
434 #define INTCAST
435 #else
436 #define INTCAST (GLint)
437 #endif
438
439
440 static void
441 sample_1d_nearest_mipmap_linear(GLcontext *ctx,
442 const struct gl_texture_object *tObj,
443 const GLfloat texcoord[4], GLfloat lambda,
444 GLchan rgba[4])
445 {
446 GLint level;
447
448 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
449
450 if (level >= tObj->_MaxLevel) {
451 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel], texcoord, rgba);
452 }
453 else {
454 GLchan t0[4], t1[4];
455 const GLfloat f = FRAC(lambda);
456 sample_1d_nearest(ctx, tObj, tObj->Image[level ], texcoord, t0);
457 sample_1d_nearest(ctx, tObj, tObj->Image[level+1], texcoord, t1);
458 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
459 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
460 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
461 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
462 }
463 }
464
465
466
467 static void
468 sample_1d_linear_mipmap_linear(GLcontext *ctx,
469 const struct gl_texture_object *tObj,
470 const GLfloat texcoord[4], GLfloat lambda,
471 GLchan rgba[4])
472 {
473 GLint level;
474
475 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
476
477 if (level >= tObj->_MaxLevel) {
478 sample_1d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], texcoord, rgba);
479 }
480 else {
481 GLchan t0[4], t1[4];
482 const GLfloat f = FRAC(lambda);
483 sample_1d_linear(ctx, tObj, tObj->Image[level ], texcoord, t0);
484 sample_1d_linear(ctx, tObj, tObj->Image[level+1], texcoord, t1);
485 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
486 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
487 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
488 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
489 }
490 }
491
492
493
494 static void
495 sample_nearest_1d( GLcontext *ctx, GLuint texUnit,
496 const struct gl_texture_object *tObj, GLuint n,
497 GLfloat texcoords[][4], const GLfloat lambda[],
498 GLchan rgba[][4] )
499 {
500 GLuint i;
501 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
502 (void) lambda;
503 for (i=0;i<n;i++) {
504 sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
505 }
506 }
507
508
509
510 static void
511 sample_linear_1d( GLcontext *ctx, GLuint texUnit,
512 const struct gl_texture_object *tObj, GLuint n,
513 GLfloat texcoords[][4], const GLfloat lambda[],
514 GLchan rgba[][4] )
515 {
516 GLuint i;
517 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
518 (void) lambda;
519 for (i=0;i<n;i++) {
520 sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
521 }
522 }
523
524
525 /*
526 * Given an (s) texture coordinate and lambda (level of detail) value,
527 * return a texture sample.
528 *
529 */
530 static void
531 sample_lambda_1d( GLcontext *ctx, GLuint texUnit,
532 const struct gl_texture_object *tObj, GLuint n,
533 GLfloat texcoords[][4],
534 const GLfloat lambda[], GLchan rgba[][4] )
535 {
536 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
537 GLuint i;
538
539 for (i=0;i<n;i++) {
540 if (lambda[i] > MinMagThresh) {
541 /* minification */
542 switch (tObj->MinFilter) {
543 case GL_NEAREST:
544 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
545 texcoords[i], rgba[i]);
546 break;
547 case GL_LINEAR:
548 sample_1d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
549 texcoords[i], rgba[i]);
550 break;
551 case GL_NEAREST_MIPMAP_NEAREST:
552 sample_1d_nearest_mipmap_nearest(ctx, tObj, texcoords[i],
553 lambda[i], rgba[i]);
554 break;
555 case GL_LINEAR_MIPMAP_NEAREST:
556 sample_1d_linear_mipmap_nearest(ctx, tObj, texcoords[i],
557 lambda[i], rgba[i]);
558 break;
559 case GL_NEAREST_MIPMAP_LINEAR:
560 sample_1d_nearest_mipmap_linear(ctx, tObj, texcoords[i],
561 lambda[i], rgba[i]);
562 break;
563 case GL_LINEAR_MIPMAP_LINEAR:
564 sample_1d_linear_mipmap_linear(ctx, tObj, texcoords[i],
565 lambda[i], rgba[i]);
566 break;
567 default:
568 _mesa_problem(NULL, "Bad min filter in sample_1d_texture");
569 return;
570 }
571 }
572 else {
573 /* magnification */
574 switch (tObj->MagFilter) {
575 case GL_NEAREST:
576 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
577 texcoords[i], rgba[i]);
578 break;
579 case GL_LINEAR:
580 sample_1d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
581 texcoords[i], rgba[i]);
582 break;
583 default:
584 _mesa_problem(NULL, "Bad mag filter in sample_1d_texture");
585 return;
586 }
587 }
588 }
589 }
590
591
592
593
594 /**********************************************************************/
595 /* 2-D Texture Sampling Functions */
596 /**********************************************************************/
597
598
599 /*
600 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
601 */
602 static void
603 sample_2d_nearest(GLcontext *ctx,
604 const struct gl_texture_object *tObj,
605 const struct gl_texture_image *img,
606 const GLfloat texcoord[4],
607 GLchan rgba[])
608 {
609 const GLint width = img->Width2; /* without border, power of two */
610 const GLint height = img->Height2; /* without border, power of two */
611 GLint i, j;
612
613 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
614 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
615
616 /* skip over the border, if any */
617 i += img->Border;
618 j += img->Border;
619
620 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
621 /* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
622 COPY_CHAN4(rgba, tObj->BorderColor);
623 }
624 else {
625 (*img->FetchTexel)(img, i, j, 0, (GLvoid *) rgba);
626 if (img->Format == GL_COLOR_INDEX) {
627 palette_sample(ctx, tObj, rgba[0], rgba);
628 }
629 }
630 }
631
632
633
634 /*
635 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
636 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
637 */
638 static void
639 sample_2d_linear(GLcontext *ctx,
640 const struct gl_texture_object *tObj,
641 const struct gl_texture_image *img,
642 const GLfloat texcoord[4],
643 GLchan rgba[])
644 {
645 const GLint width = img->Width2;
646 const GLint height = img->Height2;
647 GLint i0, j0, i1, j1;
648 GLuint useBorderColor;
649 GLfloat u, v;
650
651 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
652 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
653
654 useBorderColor = 0;
655 if (img->Border) {
656 i0 += img->Border;
657 i1 += img->Border;
658 j0 += img->Border;
659 j1 += img->Border;
660 }
661 else {
662 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
663 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
664 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
665 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
666 }
667
668 {
669 const GLfloat a = FRAC(u);
670 const GLfloat b = FRAC(v);
671
672 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
673 const GLfloat w00 = (1.0F-a) * (1.0F-b);
674 const GLfloat w10 = a * (1.0F-b);
675 const GLfloat w01 = (1.0F-a) * b ;
676 const GLfloat w11 = a * b ;
677 #else /* CHAN_BITS == 8 */
678 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
679 const GLint w00 = IROUND_POS((1.0F-a) * (1.0F-b) * WEIGHT_SCALE);
680 const GLint w10 = IROUND_POS( a * (1.0F-b) * WEIGHT_SCALE);
681 const GLint w01 = IROUND_POS((1.0F-a) * b * WEIGHT_SCALE);
682 const GLint w11 = IROUND_POS( a * b * WEIGHT_SCALE);
683 #endif
684 GLchan t00[4];
685 GLchan t10[4];
686 GLchan t01[4];
687 GLchan t11[4];
688
689 if (useBorderColor & (I0BIT | J0BIT)) {
690 COPY_CHAN4(t00, tObj->BorderColor);
691 }
692 else {
693 (*img->FetchTexel)(img, i0, j0, 0, (GLvoid *) t00);
694 if (img->Format == GL_COLOR_INDEX) {
695 palette_sample(ctx, tObj, t00[0], t00);
696 }
697 }
698 if (useBorderColor & (I1BIT | J0BIT)) {
699 COPY_CHAN4(t10, tObj->BorderColor);
700 }
701 else {
702 (*img->FetchTexel)(img, i1, j0, 0, (GLvoid *) t10);
703 if (img->Format == GL_COLOR_INDEX) {
704 palette_sample(ctx, tObj, t10[0], t10);
705 }
706 }
707 if (useBorderColor & (I0BIT | J1BIT)) {
708 COPY_CHAN4(t01, tObj->BorderColor);
709 }
710 else {
711 (*img->FetchTexel)(img, i0, j1, 0, (GLvoid *) t01);
712 if (img->Format == GL_COLOR_INDEX) {
713 palette_sample(ctx, tObj, t01[0], t01);
714 }
715 }
716 if (useBorderColor & (I1BIT | J1BIT)) {
717 COPY_CHAN4(t11, tObj->BorderColor);
718 }
719 else {
720 (*img->FetchTexel)(img, i1, j1, 0, (GLvoid *) t11);
721 if (img->Format == GL_COLOR_INDEX) {
722 palette_sample(ctx, tObj, t11[0], t11);
723 }
724 }
725 #if CHAN_TYPE == GL_FLOAT
726 rgba[0] = w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0];
727 rgba[1] = w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1];
728 rgba[2] = w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2];
729 rgba[3] = w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3];
730 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
731 rgba[0] = (GLchan) (w00 * t00[0] + w10 * t10[0] +
732 w01 * t01[0] + w11 * t11[0] + 0.5);
733 rgba[1] = (GLchan) (w00 * t00[1] + w10 * t10[1] +
734 w01 * t01[1] + w11 * t11[1] + 0.5);
735 rgba[2] = (GLchan) (w00 * t00[2] + w10 * t10[2] +
736 w01 * t01[2] + w11 * t11[2] + 0.5);
737 rgba[3] = (GLchan) (w00 * t00[3] + w10 * t10[3] +
738 w01 * t01[3] + w11 * t11[3] + 0.5);
739 #else /* CHAN_BITS == 8 */
740 rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] +
741 w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
742 rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] +
743 w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
744 rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] +
745 w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
746 rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] +
747 w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
748 #endif
749
750 }
751
752 }
753
754
755
756 static void
757 sample_2d_nearest_mipmap_nearest(GLcontext *ctx,
758 const struct gl_texture_object *tObj,
759 const GLfloat texcoord[4], GLfloat lambda,
760 GLchan rgba[4])
761 {
762 GLint level;
763 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
764 sample_2d_nearest(ctx, tObj, tObj->Image[level], texcoord, rgba);
765 }
766
767
768
769 static void
770 sample_2d_linear_mipmap_nearest(GLcontext *ctx,
771 const struct gl_texture_object *tObj,
772 const GLfloat texcoord[4], GLfloat lambda,
773 GLchan rgba[4])
774 {
775 GLint level;
776 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
777 sample_2d_linear(ctx, tObj, tObj->Image[level], texcoord, rgba);
778 }
779
780
781
782 static void
783 sample_2d_nearest_mipmap_linear(GLcontext *ctx,
784 const struct gl_texture_object *tObj,
785 const GLfloat texcoord[4], GLfloat lambda,
786 GLchan rgba[4])
787 {
788 GLint level;
789
790 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
791
792 if (level >= tObj->_MaxLevel) {
793 sample_2d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel], texcoord, rgba);
794 }
795 else {
796 GLchan t0[4], t1[4]; /* texels */
797 const GLfloat f = FRAC(lambda);
798 sample_2d_nearest(ctx, tObj, tObj->Image[level ], texcoord, t0);
799 sample_2d_nearest(ctx, tObj, tObj->Image[level+1], texcoord, t1);
800 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
801 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
802 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
803 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
804 }
805 }
806
807
808
809 static void
810 sample_2d_linear_mipmap_linear(GLcontext *ctx,
811 const struct gl_texture_object *tObj,
812 const GLfloat texcoord[4], GLfloat lambda,
813 GLchan rgba[4])
814 {
815 GLint level;
816
817 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
818
819 if (level >= tObj->_MaxLevel) {
820 sample_2d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], texcoord, rgba);
821 }
822 else {
823 GLchan t0[4], t1[4]; /* texels */
824 const GLfloat f = FRAC(lambda);
825 sample_2d_linear(ctx, tObj, tObj->Image[level ], texcoord, t0);
826 sample_2d_linear(ctx, tObj, tObj->Image[level+1], texcoord, t1);
827 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
828 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
829 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
830 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
831 }
832 }
833
834
835
836 static void
837 sample_nearest_2d( GLcontext *ctx, GLuint texUnit,
838 const struct gl_texture_object *tObj, GLuint n,
839 GLfloat texcoords[][4],
840 const GLfloat lambda[], GLchan rgba[][4] )
841 {
842 GLuint i;
843 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
844 (void) lambda;
845 for (i=0;i<n;i++) {
846 sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
847 }
848 }
849
850
851
852 static void
853 sample_linear_2d( GLcontext *ctx, GLuint texUnit,
854 const struct gl_texture_object *tObj, GLuint n,
855 GLfloat texcoords[][4],
856 const GLfloat lambda[], GLchan rgba[][4] )
857 {
858 GLuint i;
859 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
860 (void) lambda;
861 for (i=0;i<n;i++) {
862 sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
863 }
864 }
865
866
867 /*
868 * Optimized 2-D texture sampling:
869 * S and T wrap mode == GL_REPEAT
870 * GL_NEAREST min/mag filter
871 * No border
872 * Format = GL_RGB
873 */
874 static void
875 opt_sample_rgb_2d( GLcontext *ctx, GLuint texUnit,
876 const struct gl_texture_object *tObj,
877 GLuint n, GLfloat texcoords[][4],
878 const GLfloat lambda[], GLchan rgba[][4] )
879 {
880 const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
881 const GLfloat width = (GLfloat) img->Width;
882 const GLfloat height = (GLfloat) img->Height;
883 const GLint colMask = img->Width - 1;
884 const GLint rowMask = img->Height - 1;
885 const GLint shift = img->WidthLog2;
886 GLuint k;
887 (void) lambda;
888 ASSERT(tObj->WrapS==GL_REPEAT);
889 ASSERT(tObj->WrapT==GL_REPEAT);
890 ASSERT(img->Border==0);
891 ASSERT(img->Format==GL_RGB);
892
893 for (k=0; k<n; k++) {
894 GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
895 GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
896 GLint pos = (j << shift) | i;
897 GLchan *texel = ((GLchan *) img->Data) + 3*pos;
898 rgba[k][RCOMP] = texel[0];
899 rgba[k][GCOMP] = texel[1];
900 rgba[k][BCOMP] = texel[2];
901 }
902 }
903
904
905 /*
906 * Optimized 2-D texture sampling:
907 * S and T wrap mode == GL_REPEAT
908 * GL_NEAREST min/mag filter
909 * No border
910 * Format = GL_RGBA
911 */
912 static void
913 opt_sample_rgba_2d( GLcontext *ctx, GLuint texUnit,
914 const struct gl_texture_object *tObj,
915 GLuint n, GLfloat texcoords[][4],
916 const GLfloat lambda[], GLchan rgba[][4] )
917 {
918 const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
919 const GLfloat width = (GLfloat) img->Width;
920 const GLfloat height = (GLfloat) img->Height;
921 const GLint colMask = img->Width - 1;
922 const GLint rowMask = img->Height - 1;
923 const GLint shift = img->WidthLog2;
924 GLuint i;
925 (void) lambda;
926 ASSERT(tObj->WrapS==GL_REPEAT);
927 ASSERT(tObj->WrapT==GL_REPEAT);
928 ASSERT(img->Border==0);
929 ASSERT(img->Format==GL_RGBA);
930
931 for (i = 0; i < n; i++) {
932 const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
933 const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
934 const GLint pos = (row << shift) | col;
935 const GLchan *texel = ((GLchan *) img->Data) + (pos << 2); /* pos*4 */
936 COPY_CHAN4(rgba[i], texel);
937 }
938 }
939
940 #ifdef DEBUG
941 static int
942 span_is_monotonous (GLuint n, const GLfloat lambda[])
943 {
944 GLuint i;
945
946 if (n <= 1) /* array too short */
947 return GL_TRUE;
948 else if (lambda[0] >= lambda[n-1]) { /* decreasing */
949 for (i=0; i<n-1; i++)
950 if (lambda[i] < lambda[i+1])
951 return GL_FALSE;
952 }
953 else { /* increasing */
954 for (i=0; i<n-1; i++)
955 if (lambda[i] > lambda[i+1])
956 return GL_FALSE;
957 }
958
959 return GL_TRUE;
960 }
961 #endif /* DEBUG */
962
963 /*
964 * Given an array of (s,t) texture coordinate and lambda (level of detail)
965 * values, return an array of texture sample.
966 */
967 static void
968 sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
969 const struct gl_texture_object *tObj,
970 GLuint n, GLfloat texcoords[][4],
971 const GLfloat lambda[], GLchan rgba[][4] )
972 {
973 const GLfloat minMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
974 GLuint i;
975
976 #ifdef DEBUG
977 ASSERT (span_is_monotonous(n, lambda) == GL_TRUE);
978 #endif /* DEBUG */
979
980 /* since lambda is monotonous-array use this check first */
981 if (lambda[0] <= minMagThresh && lambda[n-1] <= minMagThresh) {
982 /* magnification for whole span */
983 const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
984 switch (tObj->MagFilter) {
985 case GL_NEAREST:
986 if (tObj->WrapS == GL_REPEAT && tObj->WrapT == GL_REPEAT &&
987 img->Border == 0) {
988 switch (img->Format) {
989 case GL_RGB:
990 opt_sample_rgb_2d(ctx, texUnit, tObj, n, texcoords,
991 NULL, rgba);
992 break;
993 case GL_RGBA:
994 opt_sample_rgba_2d(ctx, texUnit, tObj, n, texcoords,
995 NULL, rgba);
996 break;
997 default:
998 sample_nearest_2d(ctx, texUnit, tObj, n, texcoords,
999 NULL, rgba);
1000 }
1001 }
1002 else {
1003 sample_nearest_2d(ctx, texUnit, tObj, n, texcoords,
1004 NULL, rgba);
1005 }
1006 break;
1007 case GL_LINEAR:
1008 sample_linear_2d(ctx, texUnit, tObj, n, texcoords,
1009 NULL, rgba);
1010 break;
1011 default:
1012 _mesa_problem(NULL, "Bad mag filter in sample_lambda_2d");
1013 }
1014 }
1015 else {
1016 const struct gl_texture_image *tImg = tObj->Image[tObj->BaseLevel];
1017 for (i = 0; i < n; i++) {
1018 if (lambda[i] > minMagThresh) {
1019 /* minification */
1020 switch (tObj->MinFilter) {
1021 case GL_NEAREST:
1022 sample_2d_nearest(ctx, tObj, tImg, texcoords[i], rgba[i]);
1023 break;
1024 case GL_LINEAR:
1025 sample_2d_linear(ctx, tObj, tImg, texcoords[i], rgba[i]);
1026 break;
1027 case GL_NEAREST_MIPMAP_NEAREST:
1028 sample_2d_nearest_mipmap_nearest(ctx, tObj, texcoords[i],
1029 lambda[i], rgba[i]);
1030 break;
1031 case GL_LINEAR_MIPMAP_NEAREST:
1032 sample_2d_linear_mipmap_nearest(ctx, tObj, texcoords[i],
1033 lambda[i], rgba[i]);
1034 break;
1035 case GL_NEAREST_MIPMAP_LINEAR:
1036 sample_2d_nearest_mipmap_linear(ctx, tObj, texcoords[i],
1037 lambda[i], rgba[i]);
1038 break;
1039 case GL_LINEAR_MIPMAP_LINEAR:
1040 sample_2d_linear_mipmap_linear(ctx, tObj, texcoords[i],
1041 lambda[i], rgba[i] );
1042 break;
1043 default:
1044 _mesa_problem(NULL, "Bad min filter in sample_2d_texture");
1045 return;
1046 }
1047 }
1048 else {
1049 /* magnification */
1050 switch (tObj->MagFilter) {
1051 case GL_NEAREST:
1052 sample_2d_nearest(ctx, tObj, tImg, texcoords[i], rgba[i]);
1053 break;
1054 case GL_LINEAR:
1055 sample_2d_linear(ctx, tObj, tImg, texcoords[i], rgba[i] );
1056 break;
1057 default:
1058 _mesa_problem(NULL, "Bad mag filter in sample_2d_texture");
1059 }
1060 }
1061 }
1062 }
1063 }
1064
1065
1066
1067 /**********************************************************************/
1068 /* 3-D Texture Sampling Functions */
1069 /**********************************************************************/
1070
1071 /*
1072 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1073 */
1074 static void
1075 sample_3d_nearest(GLcontext *ctx,
1076 const struct gl_texture_object *tObj,
1077 const struct gl_texture_image *img,
1078 const GLfloat texcoord[4],
1079 GLchan rgba[4])
1080 {
1081 const GLint width = img->Width2; /* without border, power of two */
1082 const GLint height = img->Height2; /* without border, power of two */
1083 const GLint depth = img->Depth2; /* without border, power of two */
1084 GLint i, j, k;
1085
1086 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
1087 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
1088 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, texcoord[2], depth, k);
1089
1090 if (i < 0 || i >= (GLint) img->Width ||
1091 j < 0 || j >= (GLint) img->Height ||
1092 k < 0 || k >= (GLint) img->Depth) {
1093 /* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
1094 COPY_CHAN4(rgba, tObj->BorderColor);
1095 }
1096 else {
1097 (*img->FetchTexel)(img, i, j, k, (GLvoid *) rgba);
1098 if (img->Format == GL_COLOR_INDEX) {
1099 palette_sample(ctx, tObj, rgba[0], rgba);
1100 }
1101 }
1102 }
1103
1104
1105
1106 /*
1107 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1108 */
1109 static void
1110 sample_3d_linear(GLcontext *ctx,
1111 const struct gl_texture_object *tObj,
1112 const struct gl_texture_image *img,
1113 const GLfloat texcoord[4],
1114 GLchan rgba[4])
1115 {
1116 const GLint width = img->Width2;
1117 const GLint height = img->Height2;
1118 const GLint depth = img->Depth2;
1119 GLint i0, j0, k0, i1, j1, k1;
1120 GLuint useBorderColor;
1121 GLfloat u, v, w;
1122
1123 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
1124 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
1125 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, texcoord[2], w, depth, k0, k1);
1126
1127 useBorderColor = 0;
1128 if (img->Border) {
1129 i0 += img->Border;
1130 i1 += img->Border;
1131 j0 += img->Border;
1132 j1 += img->Border;
1133 k0 += img->Border;
1134 k1 += img->Border;
1135 }
1136 else {
1137 /* check if sampling texture border color */
1138 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1139 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1140 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1141 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1142 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
1143 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
1144 }
1145
1146 {
1147 const GLfloat a = FRAC(u);
1148 const GLfloat b = FRAC(v);
1149 const GLfloat c = FRAC(w);
1150
1151 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
1152 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1153 GLfloat w000 = (1.0F-a) * (1.0F-b) * (1.0F-c);
1154 GLfloat w100 = a * (1.0F-b) * (1.0F-c);
1155 GLfloat w010 = (1.0F-a) * b * (1.0F-c);
1156 GLfloat w110 = a * b * (1.0F-c);
1157 GLfloat w001 = (1.0F-a) * (1.0F-b) * c ;
1158 GLfloat w101 = a * (1.0F-b) * c ;
1159 GLfloat w011 = (1.0F-a) * b * c ;
1160 GLfloat w111 = a * b * c ;
1161 #else /* CHAN_BITS == 8 */
1162 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1163 GLint w000 = IROUND_POS((1.0F-a) * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1164 GLint w100 = IROUND_POS( a * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1165 GLint w010 = IROUND_POS((1.0F-a) * b * (1.0F-c) * WEIGHT_SCALE);
1166 GLint w110 = IROUND_POS( a * b * (1.0F-c) * WEIGHT_SCALE);
1167 GLint w001 = IROUND_POS((1.0F-a) * (1.0F-b) * c * WEIGHT_SCALE);
1168 GLint w101 = IROUND_POS( a * (1.0F-b) * c * WEIGHT_SCALE);
1169 GLint w011 = IROUND_POS((1.0F-a) * b * c * WEIGHT_SCALE);
1170 GLint w111 = IROUND_POS( a * b * c * WEIGHT_SCALE);
1171 #endif
1172
1173 GLchan t000[4], t010[4], t001[4], t011[4];
1174 GLchan t100[4], t110[4], t101[4], t111[4];
1175
1176 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
1177 COPY_CHAN4(t000, tObj->BorderColor);
1178 }
1179 else {
1180 (*img->FetchTexel)(img, i0, j0, k0, (GLvoid *) t000);
1181 if (img->Format == GL_COLOR_INDEX) {
1182 palette_sample(ctx, tObj, t000[0], t000);
1183 }
1184 }
1185 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
1186 COPY_CHAN4(t100, tObj->BorderColor);
1187 }
1188 else {
1189 (*img->FetchTexel)(img, i1, j0, k0, (GLvoid *) t100);
1190 if (img->Format == GL_COLOR_INDEX) {
1191 palette_sample(ctx, tObj, t100[0], t100);
1192 }
1193 }
1194 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
1195 COPY_CHAN4(t010, tObj->BorderColor);
1196 }
1197 else {
1198 (*img->FetchTexel)(img, i0, j1, k0, (GLvoid *) t010);
1199 if (img->Format == GL_COLOR_INDEX) {
1200 palette_sample(ctx, tObj, t010[0], t010);
1201 }
1202 }
1203 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
1204 COPY_CHAN4(t110, tObj->BorderColor);
1205 }
1206 else {
1207 (*img->FetchTexel)(img, i1, j1, k0, (GLvoid *) t110);
1208 if (img->Format == GL_COLOR_INDEX) {
1209 palette_sample(ctx, tObj, t110[0], t110);
1210 }
1211 }
1212
1213 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
1214 COPY_CHAN4(t001, tObj->BorderColor);
1215 }
1216 else {
1217 (*img->FetchTexel)(img, i0, j0, k1, (GLvoid *) t001);
1218 if (img->Format == GL_COLOR_INDEX) {
1219 palette_sample(ctx, tObj, t001[0], t001);
1220 }
1221 }
1222 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
1223 COPY_CHAN4(t101, tObj->BorderColor);
1224 }
1225 else {
1226 (*img->FetchTexel)(img, i1, j0, k1, (GLvoid *) t101);
1227 if (img->Format == GL_COLOR_INDEX) {
1228 palette_sample(ctx, tObj, t101[0], t101);
1229 }
1230 }
1231 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
1232 COPY_CHAN4(t011, tObj->BorderColor);
1233 }
1234 else {
1235 (*img->FetchTexel)(img, i0, j1, k1, (GLvoid *) t011);
1236 if (img->Format == GL_COLOR_INDEX) {
1237 palette_sample(ctx, tObj, t011[0], t011);
1238 }
1239 }
1240 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
1241 COPY_CHAN4(t111, tObj->BorderColor);
1242 }
1243 else {
1244 (*img->FetchTexel)(img, i1, j1, k1, (GLvoid *) t111);
1245 if (img->Format == GL_COLOR_INDEX) {
1246 palette_sample(ctx, tObj, t111[0], t111);
1247 }
1248 }
1249
1250 #if CHAN_TYPE == GL_FLOAT
1251 rgba[0] = w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1252 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0];
1253 rgba[1] = w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1254 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1];
1255 rgba[2] = w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1256 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2];
1257 rgba[3] = w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1258 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3];
1259 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
1260 rgba[0] = (GLchan) (w000*t000[0] + w010*t010[0] +
1261 w001*t001[0] + w011*t011[0] +
1262 w100*t100[0] + w110*t110[0] +
1263 w101*t101[0] + w111*t111[0] + 0.5);
1264 rgba[1] = (GLchan) (w000*t000[1] + w010*t010[1] +
1265 w001*t001[1] + w011*t011[1] +
1266 w100*t100[1] + w110*t110[1] +
1267 w101*t101[1] + w111*t111[1] + 0.5);
1268 rgba[2] = (GLchan) (w000*t000[2] + w010*t010[2] +
1269 w001*t001[2] + w011*t011[2] +
1270 w100*t100[2] + w110*t110[2] +
1271 w101*t101[2] + w111*t111[2] + 0.5);
1272 rgba[3] = (GLchan) (w000*t000[3] + w010*t010[3] +
1273 w001*t001[3] + w011*t011[3] +
1274 w100*t100[3] + w110*t110[3] +
1275 w101*t101[3] + w111*t111[3] + 0.5);
1276 #else /* CHAN_BITS == 8 */
1277 rgba[0] = (GLchan) (
1278 (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1279 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] )
1280 >> WEIGHT_SHIFT);
1281 rgba[1] = (GLchan) (
1282 (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1283 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
1284 >> WEIGHT_SHIFT);
1285 rgba[2] = (GLchan) (
1286 (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1287 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
1288 >> WEIGHT_SHIFT);
1289 rgba[3] = (GLchan) (
1290 (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1291 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
1292 >> WEIGHT_SHIFT);
1293 #endif
1294
1295 }
1296 }
1297
1298
1299
1300 static void
1301 sample_3d_nearest_mipmap_nearest(GLcontext *ctx,
1302 const struct gl_texture_object *tObj,
1303 const GLfloat texcoord[4],
1304 GLfloat lambda, GLchan rgba[4] )
1305 {
1306 GLint level;
1307 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1308 sample_3d_nearest(ctx, tObj, tObj->Image[level], texcoord, rgba);
1309 }
1310
1311
1312 static void
1313 sample_3d_linear_mipmap_nearest(GLcontext *ctx,
1314 const struct gl_texture_object *tObj,
1315 const GLfloat texcoord[4],
1316 GLfloat lambda, GLchan rgba[4])
1317 {
1318 GLint level;
1319 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1320 sample_3d_linear(ctx, tObj, tObj->Image[level], texcoord, rgba);
1321 }
1322
1323
1324 static void
1325 sample_3d_nearest_mipmap_linear(GLcontext *ctx,
1326 const struct gl_texture_object *tObj,
1327 const GLfloat texcoord[4],
1328 GLfloat lambda, GLchan rgba[4])
1329 {
1330 GLint level;
1331
1332 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1333
1334 if (level >= tObj->_MaxLevel) {
1335 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel],
1336 texcoord, rgba);
1337 }
1338 else {
1339 GLchan t0[4], t1[4]; /* texels */
1340 const GLfloat f = FRAC(lambda);
1341 sample_3d_nearest(ctx, tObj, tObj->Image[level ], texcoord, t0);
1342 sample_3d_nearest(ctx, tObj, tObj->Image[level+1], texcoord, t1);
1343 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1344 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1345 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1346 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1347 }
1348 }
1349
1350
1351 static void
1352 sample_3d_linear_mipmap_linear(GLcontext *ctx,
1353 const struct gl_texture_object *tObj,
1354 const GLfloat texcoord[4],
1355 GLfloat lambda, GLchan rgba[4] )
1356 {
1357 GLint level;
1358
1359 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1360
1361 if (level >= tObj->_MaxLevel) {
1362 sample_3d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], texcoord, rgba);
1363 }
1364 else {
1365 GLchan t0[4], t1[4]; /* texels */
1366 const GLfloat f = FRAC(lambda);
1367 sample_3d_linear(ctx, tObj, tObj->Image[level ], texcoord, t0);
1368 sample_3d_linear(ctx, tObj, tObj->Image[level+1], texcoord, t1);
1369 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1370 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1371 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1372 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1373 }
1374 }
1375
1376
1377 static void
1378 sample_nearest_3d(GLcontext *ctx, GLuint texUnit,
1379 const struct gl_texture_object *tObj, GLuint n,
1380 GLfloat texcoords[][4], const GLfloat lambda[],
1381 GLchan rgba[][4])
1382 {
1383 GLuint i;
1384 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
1385 (void) lambda;
1386 for (i=0;i<n;i++) {
1387 sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
1388 }
1389 }
1390
1391
1392
1393 static void
1394 sample_linear_3d( GLcontext *ctx, GLuint texUnit,
1395 const struct gl_texture_object *tObj, GLuint n,
1396 GLfloat texcoords[][4],
1397 const GLfloat lambda[], GLchan rgba[][4] )
1398 {
1399 GLuint i;
1400 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
1401 (void) lambda;
1402 for (i=0;i<n;i++) {
1403 sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
1404 }
1405 }
1406
1407
1408 /*
1409 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1410 * return a texture sample.
1411 */
1412 static void
1413 sample_lambda_3d( GLcontext *ctx, GLuint texUnit,
1414 const struct gl_texture_object *tObj, GLuint n,
1415 GLfloat texcoords[][4], const GLfloat lambda[],
1416 GLchan rgba[][4] )
1417 {
1418 GLuint i;
1419 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
1420
1421 for (i=0;i<n;i++) {
1422
1423 if (lambda[i] > MinMagThresh) {
1424 /* minification */
1425 switch (tObj->MinFilter) {
1426 case GL_NEAREST:
1427 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
1428 texcoords[i], rgba[i]);
1429 break;
1430 case GL_LINEAR:
1431 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
1432 texcoords[i], rgba[i]);
1433 break;
1434 case GL_NEAREST_MIPMAP_NEAREST:
1435 sample_3d_nearest_mipmap_nearest(ctx, tObj, texcoords[i],
1436 lambda[i], rgba[i]);
1437 break;
1438 case GL_LINEAR_MIPMAP_NEAREST:
1439 sample_3d_linear_mipmap_nearest(ctx, tObj, texcoords[i],
1440 lambda[i], rgba[i]);
1441 break;
1442 case GL_NEAREST_MIPMAP_LINEAR:
1443 sample_3d_nearest_mipmap_linear(ctx, tObj, texcoords[i],
1444 lambda[i], rgba[i]);
1445 break;
1446 case GL_LINEAR_MIPMAP_LINEAR:
1447 sample_3d_linear_mipmap_linear(ctx, tObj, texcoords[i],
1448 lambda[i], rgba[i]);
1449 break;
1450 default:
1451 _mesa_problem(NULL, "Bad min filterin sample_3d_texture");
1452 }
1453 }
1454 else {
1455 /* magnification */
1456 switch (tObj->MagFilter) {
1457 case GL_NEAREST:
1458 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
1459 texcoords[i], rgba[i]);
1460 break;
1461 case GL_LINEAR:
1462 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
1463 texcoords[i], rgba[i]);
1464 break;
1465 default:
1466 _mesa_problem(NULL, "Bad mag filter in sample_3d_texture");
1467 }
1468 }
1469 }
1470 }
1471
1472
1473 /**********************************************************************/
1474 /* Texture Cube Map Sampling Functions */
1475 /**********************************************************************/
1476
1477 /*
1478 * Choose one of six sides of a texture cube map given the texture
1479 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1480 * images.
1481 */
1482 static const struct gl_texture_image **
1483 choose_cube_face(const struct gl_texture_object *texObj,
1484 const GLfloat texcoord[4], GLfloat newCoord[4])
1485 {
1486 /*
1487 major axis
1488 direction target sc tc ma
1489 ---------- ------------------------------- --- --- ---
1490 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1491 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1492 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1493 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1494 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1495 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1496 */
1497 const GLfloat rx = texcoord[0];
1498 const GLfloat ry = texcoord[1];
1499 const GLfloat rz = texcoord[2];
1500 const struct gl_texture_image **imgArray;
1501 const GLfloat arx = ABSF(rx), ary = ABSF(ry), arz = ABSF(rz);
1502 GLfloat sc, tc, ma;
1503
1504 if (arx > ary && arx > arz) {
1505 if (rx >= 0.0F) {
1506 imgArray = (const struct gl_texture_image **) texObj->Image;
1507 sc = -rz;
1508 tc = -ry;
1509 ma = arx;
1510 }
1511 else {
1512 imgArray = (const struct gl_texture_image **) texObj->NegX;
1513 sc = rz;
1514 tc = -ry;
1515 ma = arx;
1516 }
1517 }
1518 else if (ary > arx && ary > arz) {
1519 if (ry >= 0.0F) {
1520 imgArray = (const struct gl_texture_image **) texObj->PosY;
1521 sc = rx;
1522 tc = rz;
1523 ma = ary;
1524 }
1525 else {
1526 imgArray = (const struct gl_texture_image **) texObj->NegY;
1527 sc = rx;
1528 tc = -rz;
1529 ma = ary;
1530 }
1531 }
1532 else {
1533 if (rz > 0.0F) {
1534 imgArray = (const struct gl_texture_image **) texObj->PosZ;
1535 sc = rx;
1536 tc = -ry;
1537 ma = arz;
1538 }
1539 else {
1540 imgArray = (const struct gl_texture_image **) texObj->NegZ;
1541 sc = -rx;
1542 tc = -ry;
1543 ma = arz;
1544 }
1545 }
1546
1547 newCoord[0] = ( sc / ma + 1.0F ) * 0.5F;
1548 newCoord[1] = ( tc / ma + 1.0F ) * 0.5F;
1549 return imgArray;
1550 }
1551
1552
1553 static void
1554 sample_nearest_cube(GLcontext *ctx, GLuint texUnit,
1555 const struct gl_texture_object *tObj, GLuint n,
1556 GLfloat texcoords[][4], const GLfloat lambda[],
1557 GLchan rgba[][4])
1558 {
1559 GLuint i;
1560 (void) lambda;
1561 for (i = 0; i < n; i++) {
1562 const struct gl_texture_image **images;
1563 GLfloat newCoord[4];
1564 images = choose_cube_face(tObj, texcoords[i], newCoord);
1565 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1566 newCoord, rgba[i]);
1567 }
1568 }
1569
1570
1571 static void
1572 sample_linear_cube(GLcontext *ctx, GLuint texUnit,
1573 const struct gl_texture_object *tObj, GLuint n,
1574 GLfloat texcoords[][4],
1575 const GLfloat lambda[], GLchan rgba[][4])
1576 {
1577 GLuint i;
1578 (void) lambda;
1579 for (i = 0; i < n; i++) {
1580 const struct gl_texture_image **images;
1581 GLfloat newCoord[4];
1582 images = choose_cube_face(tObj, texcoords[i], newCoord);
1583 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1584 newCoord, rgba[i]);
1585 }
1586 }
1587
1588
1589 static void
1590 sample_cube_nearest_mipmap_nearest(GLcontext *ctx,
1591 const struct gl_texture_object *tObj,
1592 const GLfloat texcoord[4],
1593 GLfloat lambda, GLchan rgba[4])
1594 {
1595 const struct gl_texture_image **images;
1596 GLfloat newCoord[4];
1597 GLint level;
1598
1599 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1600
1601 images = choose_cube_face(tObj, texcoord, newCoord);
1602 sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba);
1603 }
1604
1605
1606 static void
1607 sample_cube_linear_mipmap_nearest(GLcontext *ctx,
1608 const struct gl_texture_object *tObj,
1609 const GLfloat texcoord[4],
1610 GLfloat lambda, GLchan rgba[4])
1611 {
1612 const struct gl_texture_image **images;
1613 GLfloat newCoord[4];
1614 GLint level;
1615
1616 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1617
1618 images = choose_cube_face(tObj, texcoord, newCoord);
1619 sample_2d_linear(ctx, tObj, images[level], newCoord, rgba);
1620 }
1621
1622
1623 static void
1624 sample_cube_nearest_mipmap_linear(GLcontext *ctx,
1625 const struct gl_texture_object *tObj,
1626 const GLfloat texcoord[4],
1627 GLfloat lambda, GLchan rgba[4])
1628 {
1629 const struct gl_texture_image **images;
1630 GLfloat newCoord[4];
1631 GLint level;
1632
1633 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1634
1635 images = choose_cube_face(tObj, texcoord, newCoord);
1636
1637 if (level >= tObj->_MaxLevel) {
1638 sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], newCoord, rgba);
1639 }
1640 else {
1641 GLchan t0[4], t1[4]; /* texels */
1642 const GLfloat f = FRAC(lambda);
1643 sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0);
1644 sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1);
1645 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1646 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1647 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1648 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1649 }
1650 }
1651
1652
1653 static void
1654 sample_cube_linear_mipmap_linear(GLcontext *ctx,
1655 const struct gl_texture_object *tObj,
1656 const GLfloat texcoord[4],
1657 GLfloat lambda, GLchan rgba[4])
1658 {
1659 const struct gl_texture_image **images;
1660 GLfloat newCoord[4];
1661 GLint level;
1662
1663 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1664
1665 images = choose_cube_face(tObj, texcoord, newCoord);
1666
1667 if (level >= tObj->_MaxLevel) {
1668 sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], newCoord, rgba);
1669 }
1670 else {
1671 GLchan t0[4], t1[4];
1672 const GLfloat f = FRAC(lambda);
1673 sample_2d_linear(ctx, tObj, images[level ], newCoord, t0);
1674 sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1);
1675 rgba[RCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1676 rgba[GCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1677 rgba[BCOMP] = (GLchan) INTCAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1678 rgba[ACOMP] = (GLchan) INTCAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1679 }
1680 }
1681
1682
1683 static void
1684 sample_lambda_cube( GLcontext *ctx, GLuint texUnit,
1685 const struct gl_texture_object *tObj, GLuint n,
1686 GLfloat texcoords[][4], const GLfloat lambda[],
1687 GLchan rgba[][4])
1688 {
1689 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
1690 GLuint i;
1691
1692 for (i = 0; i < n; i++) {
1693 if (lambda[i] > MinMagThresh) {
1694 /* minification */
1695 switch (tObj->MinFilter) {
1696 case GL_NEAREST:
1697 {
1698 const struct gl_texture_image **images;
1699 GLfloat newCoord[4];
1700 images = choose_cube_face(tObj, texcoords[i], newCoord);
1701 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1702 newCoord, rgba[i]);
1703 }
1704 break;
1705 case GL_LINEAR:
1706 {
1707 const struct gl_texture_image **images;
1708 GLfloat newCoord[4];
1709 images = choose_cube_face(tObj, texcoords[i], newCoord);
1710 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1711 newCoord, rgba[i]);
1712 }
1713 break;
1714 case GL_NEAREST_MIPMAP_NEAREST:
1715 sample_cube_nearest_mipmap_nearest(ctx, tObj, texcoords[i],
1716 lambda[i], rgba[i]);
1717 break;
1718 case GL_LINEAR_MIPMAP_NEAREST:
1719 sample_cube_linear_mipmap_nearest(ctx, tObj, texcoords[i],
1720 lambda[i], rgba[i]);
1721 break;
1722 case GL_NEAREST_MIPMAP_LINEAR:
1723 sample_cube_nearest_mipmap_linear(ctx, tObj, texcoords[i],
1724 lambda[i], rgba[i]);
1725 break;
1726 case GL_LINEAR_MIPMAP_LINEAR:
1727 sample_cube_linear_mipmap_linear(ctx, tObj, texcoords[i],
1728 lambda[i], rgba[i]);
1729 break;
1730 default:
1731 _mesa_problem(NULL, "Bad min filter in sample_lambda_cube");
1732 }
1733 }
1734 else {
1735 /* magnification */
1736 const struct gl_texture_image **images;
1737 GLfloat newCoord[4];
1738 images = choose_cube_face(tObj, texcoords[i], newCoord);
1739 switch (tObj->MagFilter) {
1740 case GL_NEAREST:
1741 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1742 newCoord, rgba[i]);
1743 break;
1744 case GL_LINEAR:
1745 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1746 newCoord, rgba[i]);
1747 break;
1748 default:
1749 _mesa_problem(NULL, "Bad mag filter in sample_lambda_cube");
1750 }
1751 }
1752 }
1753 }
1754
1755
1756 /*
1757 * Sample a shadow/depth texture.
1758 */
1759 static void
1760 sample_depth_texture( GLcontext *ctx, GLuint unit,
1761 const struct gl_texture_object *tObj, GLuint n,
1762 GLfloat texcoords[][4], const GLfloat lambda[],
1763 GLchan texel[][4] )
1764 {
1765 const GLint baseLevel = tObj->BaseLevel;
1766 const struct gl_texture_image *texImage = tObj->Image[baseLevel];
1767 const GLuint width = texImage->Width;
1768 const GLuint height = texImage->Height;
1769 const GLchan ambient = tObj->ShadowAmbient;
1770 GLboolean lequal, gequal;
1771 GLchan result;
1772
1773 (void) unit;
1774
1775 ASSERT(tObj->Image[tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
1776 ASSERT(tObj->Dimensions == 1 || tObj->Dimensions == 2);
1777
1778 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
1779
1780 /* XXX this could be precomputed and saved in the texture object */
1781 if (tObj->CompareFlag) {
1782 /* GL_SGIX_shadow */
1783 if (tObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
1784 lequal = GL_TRUE;
1785 gequal = GL_FALSE;
1786 }
1787 else {
1788 ASSERT(tObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
1789 lequal = GL_FALSE;
1790 gequal = GL_TRUE;
1791 }
1792 }
1793 else if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
1794 /* GL_ARB_shadow */
1795 if (tObj->CompareFunc == GL_LEQUAL) {
1796 lequal = GL_TRUE;
1797 gequal = GL_FALSE;
1798 }
1799 else {
1800 ASSERT(tObj->CompareFunc == GL_GEQUAL);
1801 lequal = GL_FALSE;
1802 gequal = GL_TRUE;
1803 }
1804 }
1805 else {
1806 lequal = gequal = GL_FALSE;
1807 }
1808
1809 if (tObj->MagFilter == GL_NEAREST) {
1810 GLuint i;
1811 for (i = 0; i < n; i++) {
1812 GLfloat depthSample;
1813 GLint col, row;
1814 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
1815 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
1816 depthSample = *((const GLfloat *) texImage->Data + row * width + col);
1817
1818 if (lequal) {
1819 if (texcoords[i][2] <= depthSample)
1820 result = CHAN_MAX;
1821 else
1822 result = ambient;
1823 }
1824 else if (gequal) {
1825 if (texcoords[i][2] >= depthSample)
1826 result = CHAN_MAX;
1827 else
1828 result = ambient;
1829 }
1830 else {
1831 /* no comparison */
1832 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
1833 }
1834
1835 switch (tObj->DepthMode) {
1836 case GL_LUMINANCE:
1837 texel[i][RCOMP] = result;
1838 texel[i][GCOMP] = result;
1839 texel[i][BCOMP] = result;
1840 texel[i][ACOMP] = CHAN_MAX;
1841 break;
1842 case GL_INTENSITY:
1843 texel[i][RCOMP] = result;
1844 texel[i][GCOMP] = result;
1845 texel[i][BCOMP] = result;
1846 texel[i][ACOMP] = result;
1847 break;
1848 case GL_ALPHA:
1849 texel[i][RCOMP] = 0;
1850 texel[i][GCOMP] = 0;
1851 texel[i][BCOMP] = 0;
1852 texel[i][ACOMP] = result;
1853 break;
1854 default:
1855 _mesa_problem(ctx, "Bad depth texture mode");
1856 }
1857 }
1858 }
1859 else {
1860 GLuint i;
1861 ASSERT(tObj->MagFilter == GL_LINEAR);
1862 for (i = 0; i < n; i++) {
1863 GLfloat depth00, depth01, depth10, depth11;
1864 GLint i0, i1, j0, j1;
1865 GLfloat u, v;
1866 GLuint useBorderTexel;
1867
1868 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
1869 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
1870
1871 useBorderTexel = 0;
1872 if (texImage->Border) {
1873 i0 += texImage->Border;
1874 i1 += texImage->Border;
1875 j0 += texImage->Border;
1876 j1 += texImage->Border;
1877 }
1878 else {
1879 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
1880 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
1881 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
1882 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
1883 }
1884
1885 /* get four depth samples from the texture */
1886 if (useBorderTexel & (I0BIT | J0BIT)) {
1887 depth00 = 1.0;
1888 }
1889 else {
1890 depth00 = *((const GLfloat *) texImage->Data + j0 * width + i0);
1891 }
1892 if (useBorderTexel & (I1BIT | J0BIT)) {
1893 depth10 = 1.0;
1894 }
1895 else {
1896 depth10 = *((const GLfloat *) texImage->Data + j0 * width + i1);
1897 }
1898 if (useBorderTexel & (I0BIT | J1BIT)) {
1899 depth01 = 1.0;
1900 }
1901 else {
1902 depth01 = *((const GLfloat *) texImage->Data + j1 * width + i0);
1903 }
1904 if (useBorderTexel & (I1BIT | J1BIT)) {
1905 depth11 = 1.0;
1906 }
1907 else {
1908 depth11 = *((const GLfloat *) texImage->Data + j1 * width + i1);
1909 }
1910
1911 if (0) {
1912 /* compute a single weighted depth sample and do one comparison */
1913 const GLfloat a = FRAC(u + 1.0F);
1914 const GLfloat b = FRAC(v + 1.0F);
1915 const GLfloat w00 = (1.0F - a) * (1.0F - b);
1916 const GLfloat w10 = ( a) * (1.0F - b);
1917 const GLfloat w01 = (1.0F - a) * ( b);
1918 const GLfloat w11 = ( a) * ( b);
1919 const GLfloat depthSample = w00 * depth00 + w10 * depth10
1920 + w01 * depth01 + w11 * depth11;
1921 if ((depthSample <= texcoords[i][2] && lequal) ||
1922 (depthSample >= texcoords[i][2] && gequal)) {
1923 result = ambient;
1924 }
1925 else {
1926 result = CHAN_MAX;
1927 }
1928 }
1929 else {
1930 /* Do four depth/R comparisons and compute a weighted result.
1931 * If this touches on somebody's I.P., I'll remove this code
1932 * upon request.
1933 */
1934 const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
1935 GLfloat luminance = CHAN_MAXF;
1936 if (lequal) {
1937 if (depth00 <= texcoords[i][2]) luminance -= d;
1938 if (depth01 <= texcoords[i][2]) luminance -= d;
1939 if (depth10 <= texcoords[i][2]) luminance -= d;
1940 if (depth11 <= texcoords[i][2]) luminance -= d;
1941 result = (GLchan) luminance;
1942 }
1943 else if (gequal) {
1944 if (depth00 >= texcoords[i][2]) luminance -= d;
1945 if (depth01 >= texcoords[i][2]) luminance -= d;
1946 if (depth10 >= texcoords[i][2]) luminance -= d;
1947 if (depth11 >= texcoords[i][2]) luminance -= d;
1948 result = (GLchan) luminance;
1949 }
1950 else {
1951 /* no comparison, just bilinear sampling */
1952 const GLfloat a = FRAC(u + 1.0F);
1953 const GLfloat b = FRAC(v + 1.0F);
1954 const GLfloat w00 = (1.0F - a) * (1.0F - b);
1955 const GLfloat w10 = ( a) * (1.0F - b);
1956 const GLfloat w01 = (1.0F - a) * ( b);
1957 const GLfloat w11 = ( a) * ( b);
1958 const GLfloat depthSample = w00 * depth00 + w10 * depth10
1959 + w01 * depth01 + w11 * depth11;
1960 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
1961 }
1962 }
1963
1964 switch (tObj->DepthMode) {
1965 case GL_LUMINANCE:
1966 texel[i][RCOMP] = result;
1967 texel[i][GCOMP] = result;
1968 texel[i][BCOMP] = result;
1969 texel[i][ACOMP] = CHAN_MAX;
1970 break;
1971 case GL_INTENSITY:
1972 texel[i][RCOMP] = result;
1973 texel[i][GCOMP] = result;
1974 texel[i][BCOMP] = result;
1975 texel[i][ACOMP] = result;
1976 break;
1977 case GL_ALPHA:
1978 texel[i][RCOMP] = 0;
1979 texel[i][GCOMP] = 0;
1980 texel[i][BCOMP] = 0;
1981 texel[i][ACOMP] = result;
1982 break;
1983 default:
1984 _mesa_problem(ctx, "Bad depth texture mode");
1985 }
1986 } /* for */
1987 } /* if filter */
1988 }
1989
1990
1991 #if 0
1992 /*
1993 * Experimental depth texture sampling function.
1994 */
1995 static void
1996 sample_depth_texture2(const GLcontext *ctx,
1997 const struct gl_texture_unit *texUnit,
1998 GLuint n, GLfloat texcoords[][4],
1999 GLchan texel[][4])
2000 {
2001 const struct gl_texture_object *texObj = texUnit->_Current;
2002 const GLint baseLevel = texObj->BaseLevel;
2003 const struct gl_texture_image *texImage = texObj->Image[baseLevel];
2004 const GLuint width = texImage->Width;
2005 const GLuint height = texImage->Height;
2006 const GLchan ambient = texObj->ShadowAmbient;
2007 GLboolean lequal, gequal;
2008
2009 if (texObj->Dimensions != 2) {
2010 _mesa_problem(ctx, "only 2-D depth textures supported at this time");
2011 return;
2012 }
2013
2014 if (texObj->MinFilter != texObj->MagFilter) {
2015 _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
2016 return;
2017 }
2018
2019 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2020 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2021 * isn't a depth texture.
2022 */
2023 if (texImage->Format != GL_DEPTH_COMPONENT) {
2024 _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2025 return;
2026 }
2027
2028 if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2029 lequal = GL_TRUE;
2030 gequal = GL_FALSE;
2031 }
2032 else {
2033 lequal = GL_FALSE;
2034 gequal = GL_TRUE;
2035 }
2036
2037 {
2038 GLuint i;
2039 for (i = 0; i < n; i++) {
2040 const GLint K = 3;
2041 GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
2042 GLfloat w;
2043 GLchan lum;
2044 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0],
2045 width, col);
2046 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1],
2047 height, row);
2048
2049 imin = col - K;
2050 imax = col + K;
2051 jmin = row - K;
2052 jmax = row + K;
2053
2054 if (imin < 0) imin = 0;
2055 if (imax >= width) imax = width - 1;
2056 if (jmin < 0) jmin = 0;
2057 if (jmax >= height) jmax = height - 1;
2058
2059 samples = (imax - imin + 1) * (jmax - jmin + 1);
2060 count = 0;
2061 for (jj = jmin; jj <= jmax; jj++) {
2062 for (ii = imin; ii <= imax; ii++) {
2063 GLfloat depthSample = *((const GLfloat *) texImage->Data
2064 + jj * width + ii);
2065 if ((depthSample <= r[i] && lequal) ||
2066 (depthSample >= r[i] && gequal)) {
2067 count++;
2068 }
2069 }
2070 }
2071
2072 w = (GLfloat) count / (GLfloat) samples;
2073 w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
2074 lum = (GLint) w;
2075
2076 texel[i][RCOMP] = lum;
2077 texel[i][GCOMP] = lum;
2078 texel[i][BCOMP] = lum;
2079 texel[i][ACOMP] = CHAN_MAX;
2080 }
2081 }
2082 }
2083 #endif
2084
2085
2086 static void
2087 null_sample_func( GLcontext *ctx, GLuint texUnit,
2088 const struct gl_texture_object *tObj, GLuint n,
2089 GLfloat texcoords[][4], const GLfloat lambda[],
2090 GLchan rgba[][4])
2091 {
2092 }
2093
2094
2095
2096 /**********************************************************************/
2097 /* Texture Sampling Setup */
2098 /**********************************************************************/
2099
2100
2101 /*
2102 * Setup the texture sampling function for this texture object.
2103 */
2104 void
2105 _swrast_choose_texture_sample_func( GLcontext *ctx, GLuint texUnit,
2106 const struct gl_texture_object *t )
2107 {
2108 SWcontext *swrast = SWRAST_CONTEXT(ctx);
2109
2110 if (!t->Complete) {
2111 swrast->TextureSample[texUnit] = null_sample_func;
2112 }
2113 else {
2114 const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
2115 const GLenum format = t->Image[t->BaseLevel]->Format;
2116
2117 if (needLambda) {
2118 /* Compute min/mag filter threshold */
2119 if (t->MagFilter == GL_LINEAR
2120 && (t->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
2121 t->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
2122 swrast->_MinMagThresh[texUnit] = 0.5F;
2123 }
2124 else {
2125 swrast->_MinMagThresh[texUnit] = 0.0F;
2126 }
2127 }
2128
2129 switch (t->Dimensions) {
2130 case 1:
2131 if (format == GL_DEPTH_COMPONENT) {
2132 swrast->TextureSample[texUnit] = sample_depth_texture;
2133 }
2134 else if (needLambda) {
2135 swrast->TextureSample[texUnit] = sample_lambda_1d;
2136 }
2137 else if (t->MinFilter == GL_LINEAR) {
2138 swrast->TextureSample[texUnit] = sample_linear_1d;
2139 }
2140 else {
2141 ASSERT(t->MinFilter == GL_NEAREST);
2142 swrast->TextureSample[texUnit] = sample_nearest_1d;
2143 }
2144 break;
2145 case 2:
2146 if (format == GL_DEPTH_COMPONENT) {
2147 swrast->TextureSample[texUnit] = sample_depth_texture;
2148 }
2149 else if (needLambda) {
2150 swrast->TextureSample[texUnit] = sample_lambda_2d;
2151 }
2152 else if (t->MinFilter == GL_LINEAR) {
2153 swrast->TextureSample[texUnit] = sample_linear_2d;
2154 }
2155 else {
2156 GLint baseLevel = t->BaseLevel;
2157 ASSERT(t->MinFilter == GL_NEAREST);
2158 if (t->WrapS == GL_REPEAT &&
2159 t->WrapT == GL_REPEAT &&
2160 t->Image[baseLevel]->Border == 0 &&
2161 t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
2162 swrast->TextureSample[texUnit] = opt_sample_rgb_2d;
2163 }
2164 else if (t->WrapS == GL_REPEAT &&
2165 t->WrapT == GL_REPEAT &&
2166 t->Image[baseLevel]->Border == 0 &&
2167 t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
2168 swrast->TextureSample[texUnit] = opt_sample_rgba_2d;
2169 }
2170 else
2171 swrast->TextureSample[texUnit] = sample_nearest_2d;
2172 }
2173 break;
2174 case 3:
2175 if (needLambda) {
2176 swrast->TextureSample[texUnit] = sample_lambda_3d;
2177 }
2178 else if (t->MinFilter == GL_LINEAR) {
2179 swrast->TextureSample[texUnit] = sample_linear_3d;
2180 }
2181 else {
2182 ASSERT(t->MinFilter == GL_NEAREST);
2183 swrast->TextureSample[texUnit] = sample_nearest_3d;
2184 }
2185 break;
2186 case 6: /* cube map */
2187 if (needLambda) {
2188 swrast->TextureSample[texUnit] = sample_lambda_cube;
2189 }
2190 else if (t->MinFilter == GL_LINEAR) {
2191 swrast->TextureSample[texUnit] = sample_linear_cube;
2192 }
2193 else {
2194 ASSERT(t->MinFilter == GL_NEAREST);
2195 swrast->TextureSample[texUnit] = sample_nearest_cube;
2196 }
2197 break;
2198 default:
2199 _mesa_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
2200 }
2201 }
2202 }
2203
2204
2205 #define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
2206 #define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
2207
2208 static INLINE void
2209 texture_combine(const GLcontext *ctx,
2210 const struct gl_texture_unit *textureUnit,
2211 GLuint n,
2212 CONST GLchan (*primary_rgba)[4],
2213 CONST GLchan (*texel)[4],
2214 GLchan (*rgba)[4])
2215 {
2216 const GLchan (*argRGB [3])[4];
2217 const GLchan (*argA [3])[4];
2218 GLuint i, j;
2219 const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
2220 const GLuint Ashift = textureUnit->CombineScaleShiftA;
2221 #if CHAN_TYPE == GL_FLOAT
2222 const GLchan RGBmult = (GLfloat) (1 << RGBshift);
2223 const GLchan Amult = (GLfloat) (1 << Ashift);
2224 #else
2225 const GLint half = (CHAN_MAX + 1) / 2;
2226 #endif
2227
2228 DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4); /* mac 32k limitation */
2229 CHECKARRAY(ccolor, return); /* mac 32k limitation */
2230
2231 ASSERT(ctx->Extensions.EXT_texture_env_combine ||
2232 ctx->Extensions.ARB_texture_env_combine);
2233
2234 /*
2235 * Do operand setup for up to 3 operands. Loop over the terms.
2236 */
2237 for (j = 0; j < 3; j++) {
2238 switch (textureUnit->CombineSourceA[j]) {
2239 case GL_TEXTURE:
2240 argA[j] = texel;
2241 break;
2242 case GL_PRIMARY_COLOR_EXT:
2243 argA[j] = primary_rgba;
2244 break;
2245 case GL_PREVIOUS_EXT:
2246 argA[j] = (const GLchan (*)[4]) rgba;
2247 break;
2248 case GL_CONSTANT_EXT:
2249 {
2250 GLchan alpha, (*c)[4] = ccolor[j];
2251 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
2252 for (i = 0; i < n; i++)
2253 c[i][ACOMP] = alpha;
2254 argA[j] = (const GLchan (*)[4]) ccolor[j];
2255 }
2256 break;
2257 default:
2258 _mesa_problem(NULL, "invalid combine source");
2259 }
2260
2261 switch (textureUnit->CombineSourceRGB[j]) {
2262 case GL_TEXTURE:
2263 argRGB[j] = texel;
2264 break;
2265 case GL_PRIMARY_COLOR_EXT:
2266 argRGB[j] = primary_rgba;
2267 break;
2268 case GL_PREVIOUS_EXT:
2269 argRGB[j] = (const GLchan (*)[4]) rgba;
2270 break;
2271 case GL_CONSTANT_EXT:
2272 {
2273 GLchan (*c)[4] = ccolor[j];
2274 GLchan red, green, blue, alpha;
2275 UNCLAMPED_FLOAT_TO_CHAN(red, textureUnit->EnvColor[0]);
2276 UNCLAMPED_FLOAT_TO_CHAN(green, textureUnit->EnvColor[1]);
2277 UNCLAMPED_FLOAT_TO_CHAN(blue, textureUnit->EnvColor[2]);
2278 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
2279 for (i = 0; i < n; i++) {
2280 c[i][RCOMP] = red;
2281 c[i][GCOMP] = green;
2282 c[i][BCOMP] = blue;
2283 c[i][ACOMP] = alpha;
2284 }
2285 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
2286 }
2287 break;
2288 default:
2289 _mesa_problem(NULL, "invalid combine source");
2290 }
2291
2292 if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
2293 const GLchan (*src)[4] = argRGB[j];
2294 GLchan (*dst)[4] = ccolor[j];
2295
2296 /* point to new arg[j] storage */
2297 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
2298
2299 if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
2300 for (i = 0; i < n; i++) {
2301 dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
2302 dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
2303 dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
2304 }
2305 }
2306 else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) {
2307 for (i = 0; i < n; i++) {
2308 dst[i][RCOMP] = src[i][ACOMP];
2309 dst[i][GCOMP] = src[i][ACOMP];
2310 dst[i][BCOMP] = src[i][ACOMP];
2311 }
2312 }
2313 else {
2314 ASSERT(textureUnit->CombineOperandRGB[j] ==GL_ONE_MINUS_SRC_ALPHA);
2315 for (i = 0; i < n; i++) {
2316 dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
2317 dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
2318 dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
2319 }
2320 }
2321 }
2322
2323 if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
2324 const GLchan (*src)[4] = argA[j];
2325 GLchan (*dst)[4] = ccolor[j];
2326 argA[j] = (const GLchan (*)[4]) ccolor[j];
2327 for (i = 0; i < n; i++) {
2328 dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
2329 }
2330 }
2331
2332 if (textureUnit->CombineModeRGB == GL_REPLACE &&
2333 textureUnit->CombineModeA == GL_REPLACE) {
2334 break; /* done, we need only arg0 */
2335 }
2336
2337 if (j == 1 &&
2338 textureUnit->CombineModeRGB != GL_INTERPOLATE_EXT &&
2339 textureUnit->CombineModeA != GL_INTERPOLATE_EXT) {
2340 break; /* arg0 and arg1 are done. we don't need arg2. */
2341 }
2342 }
2343
2344 /*
2345 * Do the texture combine.
2346 */
2347 switch (textureUnit->CombineModeRGB) {
2348 case GL_REPLACE:
2349 {
2350 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2351 if (RGBshift) {
2352 for (i = 0; i < n; i++) {
2353 #if CHAN_TYPE == GL_FLOAT
2354 rgba[i][RCOMP] = arg0[i][RCOMP] * RGBmult;
2355 rgba[i][GCOMP] = arg0[i][GCOMP] * RGBmult;
2356 rgba[i][BCOMP] = arg0[i][BCOMP] * RGBmult;
2357 #else
2358 GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
2359 GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
2360 GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
2361 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2362 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2363 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2364 #endif
2365 }
2366 }
2367 else {
2368 for (i = 0; i < n; i++) {
2369 rgba[i][RCOMP] = arg0[i][RCOMP];
2370 rgba[i][GCOMP] = arg0[i][GCOMP];
2371 rgba[i][BCOMP] = arg0[i][BCOMP];
2372 }
2373 }
2374 }
2375 break;
2376 case GL_MODULATE:
2377 {
2378 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2379 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2380 #if CHAN_TYPE != GL_FLOAT
2381 const GLint shift = 8 - RGBshift;
2382 #endif
2383 for (i = 0; i < n; i++) {
2384 #if CHAN_TYPE == GL_FLOAT
2385 rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * RGBmult;
2386 rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * RGBmult;
2387 rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * RGBmult;
2388 #else
2389 GLuint r = PROD(arg0[i][RCOMP], arg1[i][RCOMP]) >> shift;
2390 GLuint g = PROD(arg0[i][GCOMP], arg1[i][GCOMP]) >> shift;
2391 GLuint b = PROD(arg0[i][BCOMP], arg1[i][BCOMP]) >> shift;
2392 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
2393 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
2394 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
2395 #endif
2396 }
2397 }
2398 break;
2399 case GL_ADD:
2400 {
2401 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2402 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2403 for (i = 0; i < n; i++) {
2404 #if CHAN_TYPE == GL_FLOAT
2405 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * RGBmult;
2406 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * RGBmult;
2407 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * RGBmult;
2408 #else
2409 GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
2410 GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
2411 GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
2412 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
2413 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
2414 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
2415 #endif
2416 }
2417 }
2418 break;
2419 case GL_ADD_SIGNED_EXT:
2420 {
2421 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2422 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2423 for (i = 0; i < n; i++) {
2424 #if CHAN_TYPE == GL_FLOAT
2425 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5) * RGBmult;
2426 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5) * RGBmult;
2427 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5) * RGBmult;
2428 #else
2429 GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] -half;
2430 GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] -half;
2431 GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] -half;
2432 r = (r < 0) ? 0 : r << RGBshift;
2433 g = (g < 0) ? 0 : g << RGBshift;
2434 b = (b < 0) ? 0 : b << RGBshift;
2435 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
2436 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
2437 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
2438 #endif
2439 }
2440 }
2441 break;
2442 case GL_INTERPOLATE_EXT:
2443 {
2444 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2445 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2446 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
2447 #if CHAN_TYPE != GL_FLOAT
2448 const GLint shift = 8 - RGBshift;
2449 #endif
2450 for (i = 0; i < n; i++) {
2451 #if CHAN_TYPE == GL_FLOAT
2452 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
2453 arg1[i][RCOMP] * (CHAN_MAXF - arg2[i][RCOMP])) * RGBmult;
2454 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
2455 arg1[i][GCOMP] * (CHAN_MAXF - arg2[i][GCOMP])) * RGBmult;
2456 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
2457 arg1[i][BCOMP] * (CHAN_MAXF - arg2[i][BCOMP])) * RGBmult;
2458 #else
2459 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
2460 + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
2461 >> shift;
2462 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
2463 + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
2464 >> shift;
2465 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
2466 + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
2467 >> shift;
2468 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
2469 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
2470 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
2471 #endif
2472 }
2473 }
2474 break;
2475 case GL_SUBTRACT_ARB:
2476 {
2477 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2478 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2479 for (i = 0; i < n; i++) {
2480 #if CHAN_TYPE == GL_FLOAT
2481 rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * RGBmult;
2482 rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * RGBmult;
2483 rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * RGBmult;
2484 #else
2485 GLint r = ((GLint) arg0[i][RCOMP] - (GLint) arg1[i][RCOMP]) << RGBshift;
2486 GLint g = ((GLint) arg0[i][GCOMP] - (GLint) arg1[i][GCOMP]) << RGBshift;
2487 GLint b = ((GLint) arg0[i][BCOMP] - (GLint) arg1[i][BCOMP]) << RGBshift;
2488 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
2489 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
2490 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
2491 #endif
2492 }
2493 }
2494 break;
2495 case GL_DOT3_RGB_ARB:
2496 case GL_DOT3_RGBA_ARB:
2497 {
2498 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2499 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2500 /* ATI's EXT extension has a constant scale by 4. The ARB
2501 * one will likely remove this restriction, and we should
2502 * drop the EXT extension in favour of the ARB one.
2503 */
2504 for (i = 0; i < n; i++) {
2505 #if CHAN_TYPE == GL_FLOAT
2506 GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
2507 (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
2508 (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
2509 * 4.0F;
2510 #else
2511 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
2512 (GLint)arg1[i][RCOMP] - half) +
2513 S_PROD((GLint)arg0[i][GCOMP] - half,
2514 (GLint)arg1[i][GCOMP] - half) +
2515 S_PROD((GLint)arg0[i][BCOMP] - half,
2516 (GLint)arg1[i][BCOMP] - half)) >> 6;
2517 #endif
2518 dot = CLAMP(dot, 0, CHAN_MAX);
2519 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
2520 }
2521 }
2522 break;
2523 default:
2524 _mesa_problem(NULL, "invalid combine mode");
2525 }
2526
2527 switch (textureUnit->CombineModeA) {
2528 case GL_REPLACE:
2529 {
2530 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
2531 if (Ashift) {
2532 for (i = 0; i < n; i++) {
2533 #if CHAN_TYPE == GL_FLOAT
2534 GLchan a = arg0[i][ACOMP] * Amult;
2535 #else
2536 GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
2537 #endif
2538 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
2539 }
2540 }
2541 else {
2542 for (i = 0; i < n; i++) {
2543 rgba[i][ACOMP] = arg0[i][ACOMP];
2544 }
2545 }
2546 }
2547 break;
2548 case GL_MODULATE:
2549 {
2550 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
2551 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
2552 #if CHAN_TYPE != GL_FLOAT
2553 const GLint shift = 8 - Ashift;
2554 #endif
2555 for (i = 0; i < n; i++) {
2556 #if CHAN_TYPE == GL_FLOAT
2557 rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * Amult;
2558 #else
2559 GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
2560 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
2561 #endif
2562 }
2563 }
2564 break;
2565 case GL_ADD:
2566 {
2567 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
2568 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
2569 for (i = 0; i < n; i++) {
2570 #if CHAN_TYPE == GL_FLOAT
2571 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * Amult;
2572 #else
2573 GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
2574 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
2575 #endif
2576 }
2577 }
2578 break;
2579 case GL_ADD_SIGNED_EXT:
2580 {
2581 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
2582 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
2583 for (i = 0; i < n; i++) {
2584 #if CHAN_TYPE == GL_FLOAT
2585 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * Amult;
2586 #else
2587 GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] -half;
2588 a = (a < 0) ? 0 : a << Ashift;
2589 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
2590 #endif
2591 }
2592 }
2593 break;
2594 case GL_INTERPOLATE_EXT:
2595 {
2596 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
2597 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
2598 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
2599 #if CHAN_TYPE != GL_FLOAT
2600 const GLint shift = 8 - Ashift;
2601 #endif
2602 for (i=0; i<n; i++) {
2603 #if CHAN_TYPE == GL_FLOAT
2604 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
2605 arg1[i][ACOMP] * (CHAN_MAXF - arg2[i][ACOMP]))
2606 * Amult;
2607 #else
2608 GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
2609 + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
2610 >> shift;
2611 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
2612 #endif
2613 }
2614 }
2615 break;
2616 case GL_SUBTRACT_ARB:
2617 {
2618 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
2619 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
2620 for (i = 0; i < n; i++) {
2621 #if CHAN_TYPE == GL_FLOAT
2622 rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * Amult;
2623 #else
2624 GLint a = ((GLint) arg0[i][ACOMP] - (GLint) arg1[i][ACOMP]) << RGBshift;
2625 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
2626 #endif
2627 }
2628 }
2629 break;
2630
2631 default:
2632 _mesa_problem(NULL, "invalid combine mode");
2633 }
2634
2635 /* Fix the alpha component for GL_DOT3_RGBA_EXT combining.
2636 */
2637 if (textureUnit->CombineModeRGB == GL_DOT3_RGBA_EXT ||
2638 textureUnit->CombineModeRGB == GL_DOT3_RGBA_ARB) {
2639 for (i = 0; i < n; i++) {
2640 rgba[i][ACOMP] = rgba[i][RCOMP];
2641 }
2642 }
2643 UNDEFARRAY(ccolor); /* mac 32k limitation */
2644 }
2645 #undef PROD
2646
2647
2648
2649 /**********************************************************************/
2650 /* Texture Application */
2651 /**********************************************************************/
2652
2653
2654 /*
2655 * Combine incoming fragment color with texel color to produce output color.
2656 * Input: textureUnit - pointer to texture unit to apply
2657 * format - base internal texture format
2658 * n - number of fragments
2659 * primary_rgba - primary colors (may alias rgba for single texture)
2660 * texels - array of texel colors
2661 * InOut: rgba - incoming fragment colors modified by texel colors
2662 * according to the texture environment mode.
2663 */
2664 static void
2665 apply_texture( const GLcontext *ctx,
2666 const struct gl_texture_unit *texUnit,
2667 GLuint n,
2668 CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
2669 GLchan rgba[][4] )
2670 {
2671 GLint baseLevel;
2672 GLuint i;
2673 GLint Rc, Gc, Bc, Ac;
2674 GLenum format;
2675
2676 ASSERT(texUnit);
2677 ASSERT(texUnit->_Current);
2678
2679 baseLevel = texUnit->_Current->BaseLevel;
2680 ASSERT(texUnit->_Current->Image[baseLevel]);
2681
2682 format = texUnit->_Current->Image[baseLevel]->Format;
2683
2684 if (format == GL_COLOR_INDEX || format == GL_DEPTH_COMPONENT) {
2685 format = GL_RGBA; /* a bit of a hack */
2686 }
2687
2688 switch (texUnit->EnvMode) {
2689 case GL_REPLACE:
2690 switch (format) {
2691 case GL_ALPHA:
2692 for (i=0;i<n;i++) {
2693 /* Cv = Cf */
2694 /* Av = At */
2695 rgba[i][ACOMP] = texel[i][ACOMP];
2696 }
2697 break;
2698 case GL_LUMINANCE:
2699 for (i=0;i<n;i++) {
2700 /* Cv = Lt */
2701 GLchan Lt = texel[i][RCOMP];
2702 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
2703 /* Av = Af */
2704 }
2705 break;
2706 case GL_LUMINANCE_ALPHA:
2707 for (i=0;i<n;i++) {
2708 GLchan Lt = texel[i][RCOMP];
2709 /* Cv = Lt */
2710 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
2711 /* Av = At */
2712 rgba[i][ACOMP] = texel[i][ACOMP];
2713 }
2714 break;
2715 case GL_INTENSITY:
2716 for (i=0;i<n;i++) {
2717 /* Cv = It */
2718 GLchan It = texel[i][RCOMP];
2719 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
2720 /* Av = It */
2721 rgba[i][ACOMP] = It;
2722 }
2723 break;
2724 case GL_RGB:
2725 for (i=0;i<n;i++) {
2726 /* Cv = Ct */
2727 rgba[i][RCOMP] = texel[i][RCOMP];
2728 rgba[i][GCOMP] = texel[i][GCOMP];
2729 rgba[i][BCOMP] = texel[i][BCOMP];
2730 /* Av = Af */
2731 }
2732 break;
2733 case GL_RGBA:
2734 for (i=0;i<n;i++) {
2735 /* Cv = Ct */
2736 rgba[i][RCOMP] = texel[i][RCOMP];
2737 rgba[i][GCOMP] = texel[i][GCOMP];
2738 rgba[i][BCOMP] = texel[i][BCOMP];
2739 /* Av = At */
2740 rgba[i][ACOMP] = texel[i][ACOMP];
2741 }
2742 break;
2743 default:
2744 _mesa_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
2745 return;
2746 }
2747 break;
2748
2749 case GL_MODULATE:
2750 switch (format) {
2751 case GL_ALPHA:
2752 for (i=0;i<n;i++) {
2753 /* Cv = Cf */
2754 /* Av = AfAt */
2755 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2756 }
2757 break;
2758 case GL_LUMINANCE:
2759 for (i=0;i<n;i++) {
2760 /* Cv = LtCf */
2761 GLchan Lt = texel[i][RCOMP];
2762 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
2763 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
2764 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
2765 /* Av = Af */
2766 }
2767 break;
2768 case GL_LUMINANCE_ALPHA:
2769 for (i=0;i<n;i++) {
2770 /* Cv = CfLt */
2771 GLchan Lt = texel[i][RCOMP];
2772 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
2773 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
2774 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
2775 /* Av = AfAt */
2776 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2777 }
2778 break;
2779 case GL_INTENSITY:
2780 for (i=0;i<n;i++) {
2781 /* Cv = CfIt */
2782 GLchan It = texel[i][RCOMP];
2783 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
2784 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
2785 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
2786 /* Av = AfIt */
2787 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
2788 }
2789 break;
2790 case GL_RGB:
2791 for (i=0;i<n;i++) {
2792 /* Cv = CfCt */
2793 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
2794 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
2795 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
2796 /* Av = Af */
2797 }
2798 break;
2799 case GL_RGBA:
2800 for (i=0;i<n;i++) {
2801 /* Cv = CfCt */
2802 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
2803 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
2804 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
2805 /* Av = AfAt */
2806 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2807 }
2808 break;
2809 default:
2810 _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
2811 return;
2812 }
2813 break;
2814
2815 case GL_DECAL:
2816 switch (format) {
2817 case GL_ALPHA:
2818 case GL_LUMINANCE:
2819 case GL_LUMINANCE_ALPHA:
2820 case GL_INTENSITY:
2821 /* undefined */
2822 break;
2823 case GL_RGB:
2824 for (i=0;i<n;i++) {
2825 /* Cv = Ct */
2826 rgba[i][RCOMP] = texel[i][RCOMP];
2827 rgba[i][GCOMP] = texel[i][GCOMP];
2828 rgba[i][BCOMP] = texel[i][BCOMP];
2829 /* Av = Af */
2830 }
2831 break;
2832 case GL_RGBA:
2833 for (i=0;i<n;i++) {
2834 /* Cv = Cf(1-At) + CtAt */
2835 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
2836 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
2837 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
2838 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
2839 /* Av = Af */
2840 }
2841 break;
2842 default:
2843 _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
2844 return;
2845 }
2846 break;
2847
2848 case GL_BLEND:
2849 Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
2850 Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
2851 Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
2852 Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
2853 switch (format) {
2854 case GL_ALPHA:
2855 for (i=0;i<n;i++) {
2856 /* Cv = Cf */
2857 /* Av = AfAt */
2858 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2859 }
2860 break;
2861 case GL_LUMINANCE:
2862 for (i=0;i<n;i++) {
2863 /* Cv = Cf(1-Lt) + CcLt */
2864 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
2865 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
2866 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
2867 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
2868 /* Av = Af */
2869 }
2870 break;
2871 case GL_LUMINANCE_ALPHA:
2872 for (i=0;i<n;i++) {
2873 /* Cv = Cf(1-Lt) + CcLt */
2874 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
2875 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
2876 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
2877 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
2878 /* Av = AfAt */
2879 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
2880 }
2881 break;
2882 case GL_INTENSITY:
2883 for (i=0;i<n;i++) {
2884 /* Cv = Cf(1-It) + CcLt */
2885 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
2886 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
2887 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
2888 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
2889 /* Av = Af(1-It) + Ac*It */
2890 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
2891 }
2892 break;
2893 case GL_RGB:
2894 for (i=0;i<n;i++) {
2895 /* Cv = Cf(1-Ct) + CcCt */
2896 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
2897 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
2898 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
2899 /* Av = Af */
2900 }
2901 break;
2902 case GL_RGBA:
2903 for (i=0;i<n;i++) {
2904 /* Cv = Cf(1-Ct) + CcCt */
2905 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
2906 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
2907 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
2908 /* Av = AfAt */
2909 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
2910 }
2911 break;
2912 default:
2913 _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
2914 return;
2915 }
2916 break;
2917
2918 /* XXX don't clamp results if GLchan is float??? */
2919
2920 case GL_ADD: /* GL_EXT_texture_add_env */
2921 switch (format) {
2922 case GL_ALPHA:
2923 for (i=0;i<n;i++) {
2924 /* Rv = Rf */
2925 /* Gv = Gf */
2926 /* Bv = Bf */
2927 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2928 }
2929 break;
2930 case GL_LUMINANCE:
2931 for (i=0;i<n;i++) {
2932 GLuint Lt = texel[i][RCOMP];
2933 GLuint r = rgba[i][RCOMP] + Lt;
2934 GLuint g = rgba[i][GCOMP] + Lt;
2935 GLuint b = rgba[i][BCOMP] + Lt;
2936 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2937 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2938 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2939 /* Av = Af */
2940 }
2941 break;
2942 case GL_LUMINANCE_ALPHA:
2943 for (i=0;i<n;i++) {
2944 GLuint Lt = texel[i][RCOMP];
2945 GLuint r = rgba[i][RCOMP] + Lt;
2946 GLuint g = rgba[i][GCOMP] + Lt;
2947 GLuint b = rgba[i][BCOMP] + Lt;
2948 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2949 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2950 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2951 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2952 }
2953 break;
2954 case GL_INTENSITY:
2955 for (i=0;i<n;i++) {
2956 GLchan It = texel[i][RCOMP];
2957 GLuint r = rgba[i][RCOMP] + It;
2958 GLuint g = rgba[i][GCOMP] + It;
2959 GLuint b = rgba[i][BCOMP] + It;
2960 GLuint a = rgba[i][ACOMP] + It;
2961 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2962 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2963 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2964 rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
2965 }
2966 break;
2967 case GL_RGB:
2968 for (i=0;i<n;i++) {
2969 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
2970 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
2971 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
2972 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2973 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2974 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2975 /* Av = Af */
2976 }
2977 break;
2978 case GL_RGBA:
2979 for (i=0;i<n;i++) {
2980 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
2981 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
2982 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
2983 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2984 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2985 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2986 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2987 }
2988 break;
2989 default:
2990 _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
2991 return;
2992 }
2993 break;
2994
2995 case GL_COMBINE_EXT:
2996 texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
2997 break;
2998
2999 default:
3000 _mesa_problem(ctx, "Bad env mode in apply_texture");
3001 return;
3002 }
3003 }
3004
3005
3006
3007 /*
3008 * Apply a unit of texture mapping to the incoming fragments.
3009 */
3010 void
3011 _swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
3012 GLfloat texcoords[][4], GLfloat lambda[],
3013 CONST GLchan primary_rgba[][4],
3014 GLchan rgba[][4] )
3015 {
3016 const GLuint mask = TEXTURE0_ANY << (texUnit * 4);
3017
3018 if (ctx->Texture._ReallyEnabled & mask) {
3019 const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit];
3020
3021 if (textureUnit->_Current) { /* XXX need this? */
3022 const struct gl_texture_object *curObj = textureUnit->_Current;
3023 GLchan texel[MAX_WIDTH][4];
3024
3025 if (textureUnit->LodBias != 0.0F) {
3026 /* apply LOD bias, but don't clamp yet */
3027 GLuint i;
3028 for (i=0;i<n;i++) {
3029 lambda[i] += textureUnit->LodBias;
3030 }
3031 }
3032
3033 if ((curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0)
3034 && lambda) {
3035 /* apply LOD clamping to lambda */
3036 const GLfloat min = curObj->MinLod;
3037 const GLfloat max = curObj->MaxLod;
3038 GLuint i;
3039 for (i=0;i<n;i++) {
3040 GLfloat l = lambda[i];
3041 lambda[i] = CLAMP(l, min, max);
3042 }
3043 }
3044
3045 /* Sample the texture for n fragments */
3046 SWRAST_CONTEXT(ctx)->TextureSample[texUnit]( ctx, texUnit,
3047 textureUnit->_Current,
3048 n, texcoords,
3049 lambda, texel );
3050
3051 apply_texture( ctx, textureUnit, n, primary_rgba,
3052 (const GLchan (*)[4]) texel, rgba );
3053 }
3054 }
3055 }
3056
3057
3058 /*
3059 * Apply multiple texture stages (or just unit 0) to the span.
3060 * At some point in the future we'll probably modify this so that
3061 * texels from any texture unit are available in any combiner unit.
3062 * That'll require doing all the texture sampling first, and then
3063 * all the application (blending) afterward.
3064 */
3065 void
3066 _swrast_multitexture_fragments( GLcontext *ctx, struct sw_span *span )
3067 {
3068 if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) {
3069 /* multitexture */
3070 GLchan primary_rgba[MAX_WIDTH][4];
3071 GLuint unit;
3072
3073 ASSERT(span->end < MAX_WIDTH);
3074
3075 /* save copy of the span colors (the GL_PRIMARY_COLOR) */
3076 MEMCPY(primary_rgba, span->color.rgba, 4 * span->end * sizeof(GLchan));
3077
3078 /* loop over texture units, modifying the span->color.rgba values */
3079 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
3080 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
3081 _swrast_texture_fragments( ctx, unit, span->end,
3082 span->texcoords[unit],
3083 (span->arrayMask & SPAN_LAMBDA) ?
3084 span->lambda[unit] : NULL,
3085 (CONST GLchan (*)[4]) primary_rgba,
3086 span->color.rgba );
3087 }
3088 }
3089 }
3090 else {
3091 /* Just unit 0 enabled */
3092 ASSERT(ctx->Texture._ReallyEnabled & TEXTURE0_ANY);
3093
3094 _swrast_texture_fragments( ctx, 0, span->end,
3095 span->texcoords[0],
3096 (span->arrayMask & SPAN_LAMBDA) ?
3097 span->lambda[0] : NULL,
3098 (CONST GLchan (*)[4]) span->color.rgba,
3099 span->color.rgba );
3100 }
3101 }