Fix some warnings
[mesa.git] / src / mesa / swrast / s_texture.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "glheader.h"
27 #include "context.h"
28 #include "colormac.h"
29 #include "macros.h"
30 #include "imports.h"
31 #include "pixel.h"
32 #include "texformat.h"
33 #include "teximage.h"
34
35 #include "s_context.h"
36 #include "s_texture.h"
37
38
39 /*
40 * These values are used in the fixed-point arithmetic used
41 * for linear filtering.
42 */
43 #define WEIGHT_SCALE 65536.0F
44 #define WEIGHT_SHIFT 16
45
46
47 /*
48 * Compute the remainder of a divided by b, but be careful with
49 * negative values so that GL_REPEAT mode works right.
50 */
51 static INLINE GLint
52 repeat_remainder(GLint a, GLint b)
53 {
54 if (a >= 0)
55 return a % b;
56 else
57 return (a + 1) % b + b - 1;
58 }
59
60
61 /*
62 * Used to compute texel locations for linear sampling.
63 * Input:
64 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
65 * S = texcoord in [0,1]
66 * SIZE = width (or height or depth) of texture
67 * Output:
68 * U = texcoord in [0, width]
69 * I0, I1 = two nearest texel indexes
70 */
71 #define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
72 { \
73 if (wrapMode == GL_REPEAT) { \
74 U = S * SIZE - 0.5F; \
75 if (tObj->_IsPowerOfTwo) { \
76 I0 = IFLOOR(U) & (SIZE - 1); \
77 I1 = (I0 + 1) & (SIZE - 1); \
78 } \
79 else { \
80 I0 = repeat_remainder(IFLOOR(U), SIZE); \
81 I1 = repeat_remainder(I0 + 1, SIZE); \
82 } \
83 } \
84 else if (wrapMode == GL_CLAMP_TO_EDGE) { \
85 if (S <= 0.0F) \
86 U = 0.0F; \
87 else if (S >= 1.0F) \
88 U = (GLfloat) SIZE; \
89 else \
90 U = S * SIZE; \
91 U -= 0.5F; \
92 I0 = IFLOOR(U); \
93 I1 = I0 + 1; \
94 if (I0 < 0) \
95 I0 = 0; \
96 if (I1 >= (GLint) SIZE) \
97 I1 = SIZE - 1; \
98 } \
99 else if (wrapMode == GL_CLAMP_TO_BORDER) { \
100 const GLfloat min = -1.0F / (2.0F * SIZE); \
101 const GLfloat max = 1.0F - min; \
102 if (S <= min) \
103 U = min * SIZE; \
104 else if (S >= max) \
105 U = max * SIZE; \
106 else \
107 U = S * SIZE; \
108 U -= 0.5F; \
109 I0 = IFLOOR(U); \
110 I1 = I0 + 1; \
111 } \
112 else if (wrapMode == GL_MIRRORED_REPEAT) { \
113 const GLint flr = IFLOOR(S); \
114 if (flr & 1) \
115 U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
116 else \
117 U = S - (GLfloat) flr; /* flr is even */ \
118 U = (U * SIZE) - 0.5F; \
119 I0 = IFLOOR(U); \
120 I1 = I0 + 1; \
121 if (I0 < 0) \
122 I0 = 0; \
123 if (I1 >= (GLint) SIZE) \
124 I1 = SIZE - 1; \
125 } \
126 else if (wrapMode == GL_MIRROR_CLAMP_EXT) { \
127 U = (GLfloat) fabs(S); \
128 if (U >= 1.0F) \
129 U = (GLfloat) SIZE; \
130 else \
131 U *= SIZE; \
132 U -= 0.5F; \
133 I0 = IFLOOR(U); \
134 I1 = I0 + 1; \
135 } \
136 else if (wrapMode == GL_MIRROR_CLAMP_TO_EDGE_EXT) { \
137 U = (GLfloat) fabs(S); \
138 if (U >= 1.0F) \
139 U = (GLfloat) SIZE; \
140 else \
141 U *= SIZE; \
142 U -= 0.5F; \
143 I0 = IFLOOR(U); \
144 I1 = I0 + 1; \
145 if (I0 < 0) \
146 I0 = 0; \
147 if (I1 >= (GLint) SIZE) \
148 I1 = SIZE - 1; \
149 } \
150 else if (wrapMode == GL_MIRROR_CLAMP_TO_BORDER_EXT) { \
151 const GLfloat min = -1.0F / (2.0F * SIZE); \
152 const GLfloat max = 1.0F - min; \
153 U = (GLfloat) fabs(S); \
154 if (U <= min) \
155 U = min * SIZE; \
156 else if (U >= max) \
157 U = max * SIZE; \
158 else \
159 U *= SIZE; \
160 U -= 0.5F; \
161 I0 = IFLOOR(U); \
162 I1 = I0 + 1; \
163 } \
164 else { \
165 ASSERT(wrapMode == GL_CLAMP); \
166 if (S <= 0.0F) \
167 U = 0.0F; \
168 else if (S >= 1.0F) \
169 U = (GLfloat) SIZE; \
170 else \
171 U = S * SIZE; \
172 U -= 0.5F; \
173 I0 = IFLOOR(U); \
174 I1 = I0 + 1; \
175 } \
176 }
177
178
179 /*
180 * Used to compute texel location for nearest sampling.
181 */
182 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
183 { \
184 if (wrapMode == GL_REPEAT) { \
185 /* s limited to [0,1) */ \
186 /* i limited to [0,size-1] */ \
187 I = IFLOOR(S * SIZE); \
188 if (tObj->_IsPowerOfTwo) \
189 I &= (SIZE - 1); \
190 else \
191 I = repeat_remainder(I, SIZE); \
192 } \
193 else if (wrapMode == GL_CLAMP_TO_EDGE) { \
194 /* s limited to [min,max] */ \
195 /* i limited to [0, size-1] */ \
196 const GLfloat min = 1.0F / (2.0F * SIZE); \
197 const GLfloat max = 1.0F - min; \
198 if (S < min) \
199 I = 0; \
200 else if (S > max) \
201 I = SIZE - 1; \
202 else \
203 I = IFLOOR(S * SIZE); \
204 } \
205 else if (wrapMode == GL_CLAMP_TO_BORDER) { \
206 /* s limited to [min,max] */ \
207 /* i limited to [-1, size] */ \
208 const GLfloat min = -1.0F / (2.0F * SIZE); \
209 const GLfloat max = 1.0F - min; \
210 if (S <= min) \
211 I = -1; \
212 else if (S >= max) \
213 I = SIZE; \
214 else \
215 I = IFLOOR(S * SIZE); \
216 } \
217 else if (wrapMode == GL_MIRRORED_REPEAT) { \
218 const GLfloat min = 1.0F / (2.0F * SIZE); \
219 const GLfloat max = 1.0F - min; \
220 const GLint flr = IFLOOR(S); \
221 GLfloat u; \
222 if (flr & 1) \
223 u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
224 else \
225 u = S - (GLfloat) flr; /* flr is even */ \
226 if (u < min) \
227 I = 0; \
228 else if (u > max) \
229 I = SIZE - 1; \
230 else \
231 I = IFLOOR(u * SIZE); \
232 } \
233 else if (wrapMode == GL_MIRROR_CLAMP_EXT) { \
234 /* s limited to [0,1] */ \
235 /* i limited to [0,size-1] */ \
236 const GLfloat u = (GLfloat) fabs(S); \
237 if (u <= 0.0F) \
238 I = 0; \
239 else if (u >= 1.0F) \
240 I = SIZE - 1; \
241 else \
242 I = IFLOOR(u * SIZE); \
243 } \
244 else if (wrapMode == GL_MIRROR_CLAMP_TO_EDGE_EXT) { \
245 /* s limited to [min,max] */ \
246 /* i limited to [0, size-1] */ \
247 const GLfloat min = 1.0F / (2.0F * SIZE); \
248 const GLfloat max = 1.0F - min; \
249 const GLfloat u = (GLfloat) fabs(S); \
250 if (u < min) \
251 I = 0; \
252 else if (u > max) \
253 I = SIZE - 1; \
254 else \
255 I = IFLOOR(u * SIZE); \
256 } \
257 else if (wrapMode == GL_MIRROR_CLAMP_TO_BORDER_EXT) { \
258 /* s limited to [min,max] */ \
259 /* i limited to [0, size-1] */ \
260 const GLfloat min = -1.0F / (2.0F * SIZE); \
261 const GLfloat max = 1.0F - min; \
262 const GLfloat u = (GLfloat) fabs(S); \
263 if (u < min) \
264 I = -1; \
265 else if (u > max) \
266 I = SIZE; \
267 else \
268 I = IFLOOR(u * SIZE); \
269 } \
270 else { \
271 ASSERT(wrapMode == GL_CLAMP); \
272 /* s limited to [0,1] */ \
273 /* i limited to [0,size-1] */ \
274 if (S <= 0.0F) \
275 I = 0; \
276 else if (S >= 1.0F) \
277 I = SIZE - 1; \
278 else \
279 I = IFLOOR(S * SIZE); \
280 } \
281 }
282
283
284 /* Power of two image sizes only */
285 #define COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(S, U, SIZE, I0, I1) \
286 { \
287 U = S * SIZE - 0.5F; \
288 I0 = IFLOOR(U) & (SIZE - 1); \
289 I1 = (I0 + 1) & (SIZE - 1); \
290 }
291
292
293 /*
294 * Compute linear mipmap levels for given lambda.
295 */
296 #define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level) \
297 { \
298 if (lambda < 0.0F) \
299 level = tObj->BaseLevel; \
300 else if (lambda > tObj->_MaxLambda) \
301 level = (GLint) (tObj->BaseLevel + tObj->_MaxLambda); \
302 else \
303 level = (GLint) (tObj->BaseLevel + lambda); \
304 }
305
306
307 /*
308 * Compute nearest mipmap level for given lambda.
309 */
310 #define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \
311 { \
312 GLfloat l; \
313 if (lambda <= 0.5F) \
314 l = 0.0F; \
315 else if (lambda > tObj->_MaxLambda + 0.4999F) \
316 l = tObj->_MaxLambda + 0.4999F; \
317 else \
318 l = lambda; \
319 level = (GLint) (tObj->BaseLevel + l + 0.5F); \
320 if (level > tObj->_MaxLevel) \
321 level = tObj->_MaxLevel; \
322 }
323
324
325
326 /*
327 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
328 * see 1-pixel bands of improperly weighted linear-sampled texels. The
329 * tests/texwrap.c demo is a good test.
330 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
331 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
332 */
333 #define FRAC(f) ((f) - IFLOOR(f))
334
335
336
337 /*
338 * Bitflags for texture border color sampling.
339 */
340 #define I0BIT 1
341 #define I1BIT 2
342 #define J0BIT 4
343 #define J1BIT 8
344 #define K0BIT 16
345 #define K1BIT 32
346
347
348
349 /*
350 * The lambda[] array values are always monotonic. Either the whole span
351 * will be minified, magnified, or split between the two. This function
352 * determines the subranges in [0, n-1] that are to be minified or magnified.
353 */
354 static INLINE void
355 compute_min_mag_ranges( GLfloat minMagThresh, GLuint n, const GLfloat lambda[],
356 GLuint *minStart, GLuint *minEnd,
357 GLuint *magStart, GLuint *magEnd )
358 {
359 ASSERT(lambda != NULL);
360 #if 0
361 /* Verify that lambda[] is monotonous.
362 * We can't really use this because the inaccuracy in the LOG2 function
363 * causes this test to fail, yet the resulting texturing is correct.
364 */
365 if (n > 1) {
366 GLuint i;
367 printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
368 if (lambda[0] >= lambda[n-1]) { /* decreasing */
369 for (i = 0; i < n - 1; i++) {
370 ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
371 }
372 }
373 else { /* increasing */
374 for (i = 0; i < n - 1; i++) {
375 ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
376 }
377 }
378 }
379 #endif /* DEBUG */
380
381 /* since lambda is monotonous-array use this check first */
382 if (lambda[0] <= minMagThresh && lambda[n-1] <= minMagThresh) {
383 /* magnification for whole span */
384 *magStart = 0;
385 *magEnd = n;
386 *minStart = *minEnd = 0;
387 }
388 else if (lambda[0] > minMagThresh && lambda[n-1] > minMagThresh) {
389 /* minification for whole span */
390 *minStart = 0;
391 *minEnd = n;
392 *magStart = *magEnd = 0;
393 }
394 else {
395 /* a mix of minification and magnification */
396 GLuint i;
397 if (lambda[0] > minMagThresh) {
398 /* start with minification */
399 for (i = 1; i < n; i++) {
400 if (lambda[i] <= minMagThresh)
401 break;
402 }
403 *minStart = 0;
404 *minEnd = i;
405 *magStart = i;
406 *magEnd = n;
407 }
408 else {
409 /* start with magnification */
410 for (i = 1; i < n; i++) {
411 if (lambda[i] > minMagThresh)
412 break;
413 }
414 *magStart = 0;
415 *magEnd = i;
416 *minStart = i;
417 *minEnd = n;
418 }
419 }
420
421 #if 0
422 /* Verify the min/mag Start/End values
423 * We don't use this either (see above)
424 */
425 {
426 GLint i;
427 for (i = 0; i < n; i++) {
428 if (lambda[i] > minMagThresh) {
429 /* minification */
430 ASSERT(i >= *minStart);
431 ASSERT(i < *minEnd);
432 }
433 else {
434 /* magnification */
435 ASSERT(i >= *magStart);
436 ASSERT(i < *magEnd);
437 }
438 }
439 }
440 #endif
441 }
442
443
444 /**********************************************************************/
445 /* 1-D Texture Sampling Functions */
446 /**********************************************************************/
447
448 /*
449 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
450 */
451 static void
452 sample_1d_nearest(GLcontext *ctx,
453 const struct gl_texture_object *tObj,
454 const struct gl_texture_image *img,
455 const GLfloat texcoord[4], GLchan rgba[4])
456 {
457 const GLint width = img->Width2; /* without border, power of two */
458 GLint i;
459 (void) ctx;
460
461 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
462
463 /* skip over the border, if any */
464 i += img->Border;
465
466 if (i < 0 || i >= (GLint) img->Width) {
467 /* Need this test for GL_CLAMP_TO_BORDER mode */
468 COPY_CHAN4(rgba, tObj->_BorderChan);
469 }
470 else {
471 img->FetchTexelc(img, i, 0, 0, rgba);
472 }
473 }
474
475
476
477 /*
478 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
479 */
480 static void
481 sample_1d_linear(GLcontext *ctx,
482 const struct gl_texture_object *tObj,
483 const struct gl_texture_image *img,
484 const GLfloat texcoord[4], GLchan rgba[4])
485 {
486 const GLint width = img->Width2;
487 GLint i0, i1;
488 GLfloat u;
489 GLuint useBorderColor;
490 (void) ctx;
491
492 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
493
494 useBorderColor = 0;
495 if (img->Border) {
496 i0 += img->Border;
497 i1 += img->Border;
498 }
499 else {
500 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
501 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
502 }
503
504 {
505 const GLfloat a = FRAC(u);
506
507 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
508 const GLfloat w0 = (1.0F-a);
509 const GLfloat w1 = a ;
510 #else /* CHAN_BITS == 8 */
511 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
512 const GLint w0 = IROUND_POS((1.0F - a) * WEIGHT_SCALE);
513 const GLint w1 = IROUND_POS( a * WEIGHT_SCALE);
514 #endif
515 GLchan t0[4], t1[4]; /* texels */
516
517 if (useBorderColor & I0BIT) {
518 COPY_CHAN4(t0, tObj->_BorderChan);
519 }
520 else {
521 img->FetchTexelc(img, i0, 0, 0, t0);
522 }
523 if (useBorderColor & I1BIT) {
524 COPY_CHAN4(t1, tObj->_BorderChan);
525 }
526 else {
527 img->FetchTexelc(img, i1, 0, 0, t1);
528 }
529
530 #if CHAN_TYPE == GL_FLOAT
531 rgba[0] = w0 * t0[0] + w1 * t1[0];
532 rgba[1] = w0 * t0[1] + w1 * t1[1];
533 rgba[2] = w0 * t0[2] + w1 * t1[2];
534 rgba[3] = w0 * t0[3] + w1 * t1[3];
535 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
536 rgba[0] = (GLchan) (w0 * t0[0] + w1 * t1[0] + 0.5);
537 rgba[1] = (GLchan) (w0 * t0[1] + w1 * t1[1] + 0.5);
538 rgba[2] = (GLchan) (w0 * t0[2] + w1 * t1[2] + 0.5);
539 rgba[3] = (GLchan) (w0 * t0[3] + w1 * t1[3] + 0.5);
540 #else /* CHAN_BITS == 8 */
541 rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT);
542 rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT);
543 rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT);
544 rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT);
545 #endif
546
547 }
548 }
549
550
551 static void
552 sample_1d_nearest_mipmap_nearest(GLcontext *ctx,
553 const struct gl_texture_object *tObj,
554 GLuint n, const GLfloat texcoord[][4],
555 const GLfloat lambda[], GLchan rgba[][4])
556 {
557 GLuint i;
558 ASSERT(lambda != NULL);
559 for (i = 0; i < n; i++) {
560 GLint level;
561 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
562 sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
563 }
564 }
565
566
567 static void
568 sample_1d_linear_mipmap_nearest(GLcontext *ctx,
569 const struct gl_texture_object *tObj,
570 GLuint n, const GLfloat texcoord[][4],
571 const GLfloat lambda[], GLchan rgba[][4])
572 {
573 GLuint i;
574 ASSERT(lambda != NULL);
575 for (i = 0; i < n; i++) {
576 GLint level;
577 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
578 sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
579 }
580 }
581
582
583
584 /*
585 * This is really just needed in order to prevent warnings with some compilers.
586 */
587 #if CHAN_TYPE == GL_FLOAT
588 #define CHAN_CAST
589 #else
590 #define CHAN_CAST (GLchan) (GLint)
591 #endif
592
593
594 static void
595 sample_1d_nearest_mipmap_linear(GLcontext *ctx,
596 const struct gl_texture_object *tObj,
597 GLuint n, const GLfloat texcoord[][4],
598 const GLfloat lambda[], GLchan rgba[][4])
599 {
600 GLuint i;
601 ASSERT(lambda != NULL);
602 for (i = 0; i < n; i++) {
603 GLint level;
604 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
605 if (level >= tObj->_MaxLevel) {
606 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
607 texcoord[i], rgba[i]);
608 }
609 else {
610 GLchan t0[4], t1[4];
611 const GLfloat f = FRAC(lambda[i]);
612 sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
613 sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
614 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
615 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
616 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
617 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
618 }
619 }
620 }
621
622
623
624 static void
625 sample_1d_linear_mipmap_linear(GLcontext *ctx,
626 const struct gl_texture_object *tObj,
627 GLuint n, const GLfloat texcoord[][4],
628 const GLfloat lambda[], GLchan rgba[][4])
629 {
630 GLuint i;
631 ASSERT(lambda != NULL);
632 for (i = 0; i < n; i++) {
633 GLint level;
634 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
635 if (level >= tObj->_MaxLevel) {
636 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
637 texcoord[i], rgba[i]);
638 }
639 else {
640 GLchan t0[4], t1[4];
641 const GLfloat f = FRAC(lambda[i]);
642 sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
643 sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
644 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
645 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
646 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
647 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
648 }
649 }
650 }
651
652
653
654 static void
655 sample_nearest_1d( GLcontext *ctx, GLuint texUnit,
656 const struct gl_texture_object *tObj, GLuint n,
657 const GLfloat texcoords[][4], const GLfloat lambda[],
658 GLchan rgba[][4] )
659 {
660 GLuint i;
661 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
662 (void) texUnit;
663 (void) lambda;
664 for (i=0;i<n;i++) {
665 sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
666 }
667 }
668
669
670
671 static void
672 sample_linear_1d( GLcontext *ctx, GLuint texUnit,
673 const struct gl_texture_object *tObj, GLuint n,
674 const GLfloat texcoords[][4], const GLfloat lambda[],
675 GLchan rgba[][4] )
676 {
677 GLuint i;
678 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
679 (void) texUnit;
680 (void) lambda;
681 for (i=0;i<n;i++) {
682 sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
683 }
684 }
685
686
687 /*
688 * Given an (s) texture coordinate and lambda (level of detail) value,
689 * return a texture sample.
690 *
691 */
692 static void
693 sample_lambda_1d( GLcontext *ctx, GLuint texUnit,
694 const struct gl_texture_object *tObj, GLuint n,
695 const GLfloat texcoords[][4],
696 const GLfloat lambda[], GLchan rgba[][4] )
697 {
698 GLuint minStart, minEnd; /* texels with minification */
699 GLuint magStart, magEnd; /* texels with magnification */
700 GLuint i;
701
702 ASSERT(lambda != NULL);
703 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
704 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
705
706 if (minStart < minEnd) {
707 /* do the minified texels */
708 const GLuint m = minEnd - minStart;
709 switch (tObj->MinFilter) {
710 case GL_NEAREST:
711 for (i = minStart; i < minEnd; i++)
712 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
713 texcoords[i], rgba[i]);
714 break;
715 case GL_LINEAR:
716 for (i = minStart; i < minEnd; i++)
717 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
718 texcoords[i], rgba[i]);
719 break;
720 case GL_NEAREST_MIPMAP_NEAREST:
721 sample_1d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
722 lambda + minStart, rgba + minStart);
723 break;
724 case GL_LINEAR_MIPMAP_NEAREST:
725 sample_1d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
726 lambda + minStart, rgba + minStart);
727 break;
728 case GL_NEAREST_MIPMAP_LINEAR:
729 sample_1d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
730 lambda + minStart, rgba + minStart);
731 break;
732 case GL_LINEAR_MIPMAP_LINEAR:
733 sample_1d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
734 lambda + minStart, rgba + minStart);
735 break;
736 default:
737 _mesa_problem(ctx, "Bad min filter in sample_1d_texture");
738 return;
739 }
740 }
741
742 if (magStart < magEnd) {
743 /* do the magnified texels */
744 switch (tObj->MagFilter) {
745 case GL_NEAREST:
746 for (i = magStart; i < magEnd; i++)
747 sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
748 texcoords[i], rgba[i]);
749 break;
750 case GL_LINEAR:
751 for (i = magStart; i < magEnd; i++)
752 sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
753 texcoords[i], rgba[i]);
754 break;
755 default:
756 _mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
757 return;
758 }
759 }
760 }
761
762
763 /**********************************************************************/
764 /* 2-D Texture Sampling Functions */
765 /**********************************************************************/
766
767
768 /*
769 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
770 */
771 static INLINE void
772 sample_2d_nearest(GLcontext *ctx,
773 const struct gl_texture_object *tObj,
774 const struct gl_texture_image *img,
775 const GLfloat texcoord[4],
776 GLchan rgba[])
777 {
778 const GLint width = img->Width2; /* without border, power of two */
779 const GLint height = img->Height2; /* without border, power of two */
780 GLint i, j;
781 (void) ctx;
782
783 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
784 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
785
786 /* skip over the border, if any */
787 i += img->Border;
788 j += img->Border;
789
790 if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
791 /* Need this test for GL_CLAMP_TO_BORDER mode */
792 COPY_CHAN4(rgba, tObj->_BorderChan);
793 }
794 else {
795 img->FetchTexelc(img, i, j, 0, rgba);
796 }
797 }
798
799
800
801 /*
802 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
803 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
804 */
805 static INLINE void
806 sample_2d_linear(GLcontext *ctx,
807 const struct gl_texture_object *tObj,
808 const struct gl_texture_image *img,
809 const GLfloat texcoord[4],
810 GLchan rgba[])
811 {
812 const GLint width = img->Width2;
813 const GLint height = img->Height2;
814 GLint i0, j0, i1, j1;
815 GLuint useBorderColor;
816 GLfloat u, v;
817 (void) ctx;
818
819 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
820 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
821
822 useBorderColor = 0;
823 if (img->Border) {
824 i0 += img->Border;
825 i1 += img->Border;
826 j0 += img->Border;
827 j1 += img->Border;
828 }
829 else {
830 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
831 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
832 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
833 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
834 }
835
836 {
837 const GLfloat a = FRAC(u);
838 const GLfloat b = FRAC(v);
839
840 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
841 const GLfloat w00 = (1.0F-a) * (1.0F-b);
842 const GLfloat w10 = a * (1.0F-b);
843 const GLfloat w01 = (1.0F-a) * b ;
844 const GLfloat w11 = a * b ;
845 #else /* CHAN_BITS == 8 */
846 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
847 const GLint w00 = IROUND_POS((1.0F-a) * (1.0F-b) * WEIGHT_SCALE);
848 const GLint w10 = IROUND_POS( a * (1.0F-b) * WEIGHT_SCALE);
849 const GLint w01 = IROUND_POS((1.0F-a) * b * WEIGHT_SCALE);
850 const GLint w11 = IROUND_POS( a * b * WEIGHT_SCALE);
851 #endif
852 GLchan t00[4];
853 GLchan t10[4];
854 GLchan t01[4];
855 GLchan t11[4];
856
857 if (useBorderColor & (I0BIT | J0BIT)) {
858 COPY_CHAN4(t00, tObj->_BorderChan);
859 }
860 else {
861 img->FetchTexelc(img, i0, j0, 0, t00);
862 }
863 if (useBorderColor & (I1BIT | J0BIT)) {
864 COPY_CHAN4(t10, tObj->_BorderChan);
865 }
866 else {
867 img->FetchTexelc(img, i1, j0, 0, t10);
868 }
869 if (useBorderColor & (I0BIT | J1BIT)) {
870 COPY_CHAN4(t01, tObj->_BorderChan);
871 }
872 else {
873 img->FetchTexelc(img, i0, j1, 0, t01);
874 }
875 if (useBorderColor & (I1BIT | J1BIT)) {
876 COPY_CHAN4(t11, tObj->_BorderChan);
877 }
878 else {
879 img->FetchTexelc(img, i1, j1, 0, t11);
880 }
881 #if CHAN_TYPE == GL_FLOAT
882 rgba[0] = w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0];
883 rgba[1] = w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1];
884 rgba[2] = w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2];
885 rgba[3] = w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3];
886 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
887 rgba[0] = (GLchan) (w00 * t00[0] + w10 * t10[0] +
888 w01 * t01[0] + w11 * t11[0] + 0.5);
889 rgba[1] = (GLchan) (w00 * t00[1] + w10 * t10[1] +
890 w01 * t01[1] + w11 * t11[1] + 0.5);
891 rgba[2] = (GLchan) (w00 * t00[2] + w10 * t10[2] +
892 w01 * t01[2] + w11 * t11[2] + 0.5);
893 rgba[3] = (GLchan) (w00 * t00[3] + w10 * t10[3] +
894 w01 * t01[3] + w11 * t11[3] + 0.5);
895 #else /* CHAN_BITS == 8 */
896 rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] +
897 w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
898 rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] +
899 w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
900 rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] +
901 w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
902 rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] +
903 w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
904 #endif
905
906 }
907
908 }
909
910
911 /*
912 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT
913 * and we're not using a paletted texture.
914 */
915 static INLINE void
916 sample_2d_linear_repeat(GLcontext *ctx,
917 const struct gl_texture_object *tObj,
918 const struct gl_texture_image *img,
919 const GLfloat texcoord[4],
920 GLchan rgba[])
921 {
922 const GLint width = img->Width2;
923 const GLint height = img->Height2;
924 GLint i0, j0, i1, j1;
925 GLfloat u, v;
926 (void) ctx;
927 (void) tObj;
928
929 ASSERT(tObj->WrapS == GL_REPEAT);
930 ASSERT(tObj->WrapT == GL_REPEAT);
931 ASSERT(img->Border == 0);
932 ASSERT(img->Format != GL_COLOR_INDEX);
933 ASSERT(img->_IsPowerOfTwo);
934
935 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord[0], u, width, i0, i1);
936 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord[1], v, height, j0, j1);
937
938 {
939 const GLfloat a = FRAC(u);
940 const GLfloat b = FRAC(v);
941
942 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
943 const GLfloat w00 = (1.0F-a) * (1.0F-b);
944 const GLfloat w10 = a * (1.0F-b);
945 const GLfloat w01 = (1.0F-a) * b ;
946 const GLfloat w11 = a * b ;
947 #else /* CHAN_BITS == 8 */
948 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
949 const GLint w00 = IROUND_POS((1.0F-a) * (1.0F-b) * WEIGHT_SCALE);
950 const GLint w10 = IROUND_POS( a * (1.0F-b) * WEIGHT_SCALE);
951 const GLint w01 = IROUND_POS((1.0F-a) * b * WEIGHT_SCALE);
952 const GLint w11 = IROUND_POS( a * b * WEIGHT_SCALE);
953 #endif
954 GLchan t00[4];
955 GLchan t10[4];
956 GLchan t01[4];
957 GLchan t11[4];
958
959 img->FetchTexelc(img, i0, j0, 0, t00);
960 img->FetchTexelc(img, i1, j0, 0, t10);
961 img->FetchTexelc(img, i0, j1, 0, t01);
962 img->FetchTexelc(img, i1, j1, 0, t11);
963
964 #if CHAN_TYPE == GL_FLOAT
965 rgba[0] = w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0];
966 rgba[1] = w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1];
967 rgba[2] = w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2];
968 rgba[3] = w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3];
969 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
970 rgba[0] = (GLchan) (w00 * t00[0] + w10 * t10[0] +
971 w01 * t01[0] + w11 * t11[0] + 0.5);
972 rgba[1] = (GLchan) (w00 * t00[1] + w10 * t10[1] +
973 w01 * t01[1] + w11 * t11[1] + 0.5);
974 rgba[2] = (GLchan) (w00 * t00[2] + w10 * t10[2] +
975 w01 * t01[2] + w11 * t11[2] + 0.5);
976 rgba[3] = (GLchan) (w00 * t00[3] + w10 * t10[3] +
977 w01 * t01[3] + w11 * t11[3] + 0.5);
978 #else /* CHAN_BITS == 8 */
979 rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] +
980 w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
981 rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] +
982 w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
983 rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] +
984 w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
985 rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] +
986 w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
987 #endif
988
989 }
990
991 }
992
993
994
995 static void
996 sample_2d_nearest_mipmap_nearest(GLcontext *ctx,
997 const struct gl_texture_object *tObj,
998 GLuint n, const GLfloat texcoord[][4],
999 const GLfloat lambda[], GLchan rgba[][4])
1000 {
1001 GLuint i;
1002 for (i = 0; i < n; i++) {
1003 GLint level;
1004 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1005 sample_2d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1006 }
1007 }
1008
1009
1010
1011 static void
1012 sample_2d_linear_mipmap_nearest(GLcontext *ctx,
1013 const struct gl_texture_object *tObj,
1014 GLuint n, const GLfloat texcoord[][4],
1015 const GLfloat lambda[], GLchan rgba[][4])
1016 {
1017 GLuint i;
1018 ASSERT(lambda != NULL);
1019 for (i = 0; i < n; i++) {
1020 GLint level;
1021 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1022 sample_2d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1023 }
1024 }
1025
1026
1027
1028 static void
1029 sample_2d_nearest_mipmap_linear(GLcontext *ctx,
1030 const struct gl_texture_object *tObj,
1031 GLuint n, const GLfloat texcoord[][4],
1032 const GLfloat lambda[], GLchan rgba[][4])
1033 {
1034 GLuint i;
1035 ASSERT(lambda != NULL);
1036 for (i = 0; i < n; i++) {
1037 GLint level;
1038 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1039 if (level >= tObj->_MaxLevel) {
1040 sample_2d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1041 texcoord[i], rgba[i]);
1042 }
1043 else {
1044 GLchan t0[4], t1[4]; /* texels */
1045 const GLfloat f = FRAC(lambda[i]);
1046 sample_2d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1047 sample_2d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1048 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1049 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1050 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1051 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1052 }
1053 }
1054 }
1055
1056
1057
1058 /* Trilinear filtering */
1059 static void
1060 sample_2d_linear_mipmap_linear( GLcontext *ctx,
1061 const struct gl_texture_object *tObj,
1062 GLuint n, const GLfloat texcoord[][4],
1063 const GLfloat lambda[], GLchan rgba[][4] )
1064 {
1065 GLuint i;
1066 ASSERT(lambda != NULL);
1067 for (i = 0; i < n; i++) {
1068 GLint level;
1069 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1070 if (level >= tObj->_MaxLevel) {
1071 sample_2d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1072 texcoord[i], rgba[i]);
1073 }
1074 else {
1075 GLchan t0[4], t1[4]; /* texels */
1076 const GLfloat f = FRAC(lambda[i]);
1077 sample_2d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1078 sample_2d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1079 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1080 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1081 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1082 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1083 }
1084 }
1085 }
1086
1087
1088 static void
1089 sample_2d_linear_mipmap_linear_repeat( GLcontext *ctx,
1090 const struct gl_texture_object *tObj,
1091 GLuint n, const GLfloat texcoord[][4],
1092 const GLfloat lambda[], GLchan rgba[][4] )
1093 {
1094 GLuint i;
1095 ASSERT(lambda != NULL);
1096 ASSERT(tObj->WrapS == GL_REPEAT);
1097 ASSERT(tObj->WrapT == GL_REPEAT);
1098 ASSERT(tObj->_IsPowerOfTwo);
1099 for (i = 0; i < n; i++) {
1100 GLint level;
1101 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1102 if (level >= tObj->_MaxLevel) {
1103 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1104 texcoord[i], rgba[i]);
1105 }
1106 else {
1107 GLchan t0[4], t1[4]; /* texels */
1108 const GLfloat f = FRAC(lambda[i]);
1109 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1110 sample_2d_linear_repeat(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1111 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1112 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1113 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1114 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1115 }
1116 }
1117 }
1118
1119
1120 static void
1121 sample_nearest_2d( GLcontext *ctx, GLuint texUnit,
1122 const struct gl_texture_object *tObj, GLuint n,
1123 const GLfloat texcoords[][4],
1124 const GLfloat lambda[], GLchan rgba[][4] )
1125 {
1126 GLuint i;
1127 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1128 (void) texUnit;
1129 (void) lambda;
1130 for (i=0;i<n;i++) {
1131 sample_2d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
1132 }
1133 }
1134
1135
1136
1137 static void
1138 sample_linear_2d( GLcontext *ctx, GLuint texUnit,
1139 const struct gl_texture_object *tObj, GLuint n,
1140 const GLfloat texcoords[][4],
1141 const GLfloat lambda[], GLchan rgba[][4] )
1142 {
1143 GLuint i;
1144 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1145 (void) texUnit;
1146 (void) lambda;
1147 for (i=0;i<n;i++) {
1148 sample_2d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
1149 }
1150 }
1151
1152
1153 /*
1154 * Optimized 2-D texture sampling:
1155 * S and T wrap mode == GL_REPEAT
1156 * GL_NEAREST min/mag filter
1157 * No border,
1158 * RowStride == Width,
1159 * Format = GL_RGB
1160 */
1161 static void
1162 opt_sample_rgb_2d( GLcontext *ctx, GLuint texUnit,
1163 const struct gl_texture_object *tObj,
1164 GLuint n, const GLfloat texcoords[][4],
1165 const GLfloat lambda[], GLchan rgba[][4] )
1166 {
1167 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1168 const GLfloat width = (GLfloat) img->Width;
1169 const GLfloat height = (GLfloat) img->Height;
1170 const GLint colMask = img->Width - 1;
1171 const GLint rowMask = img->Height - 1;
1172 const GLint shift = img->WidthLog2;
1173 GLuint k;
1174 (void) ctx;
1175 (void) texUnit;
1176 (void) lambda;
1177 ASSERT(tObj->WrapS==GL_REPEAT);
1178 ASSERT(tObj->WrapT==GL_REPEAT);
1179 ASSERT(img->Border==0);
1180 ASSERT(img->Format==GL_RGB);
1181 ASSERT(img->_IsPowerOfTwo);
1182
1183 for (k=0; k<n; k++) {
1184 GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
1185 GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
1186 GLint pos = (j << shift) | i;
1187 GLchan *texel = ((GLchan *) img->Data) + 3*pos;
1188 rgba[k][RCOMP] = texel[0];
1189 rgba[k][GCOMP] = texel[1];
1190 rgba[k][BCOMP] = texel[2];
1191 }
1192 }
1193
1194
1195 /*
1196 * Optimized 2-D texture sampling:
1197 * S and T wrap mode == GL_REPEAT
1198 * GL_NEAREST min/mag filter
1199 * No border
1200 * RowStride == Width,
1201 * Format = GL_RGBA
1202 */
1203 static void
1204 opt_sample_rgba_2d( GLcontext *ctx, GLuint texUnit,
1205 const struct gl_texture_object *tObj,
1206 GLuint n, const GLfloat texcoords[][4],
1207 const GLfloat lambda[], GLchan rgba[][4] )
1208 {
1209 const struct gl_texture_image *img = tObj->Image[0][tObj->BaseLevel];
1210 const GLfloat width = (GLfloat) img->Width;
1211 const GLfloat height = (GLfloat) img->Height;
1212 const GLint colMask = img->Width - 1;
1213 const GLint rowMask = img->Height - 1;
1214 const GLint shift = img->WidthLog2;
1215 GLuint i;
1216 (void) ctx;
1217 (void) texUnit;
1218 (void) lambda;
1219 ASSERT(tObj->WrapS==GL_REPEAT);
1220 ASSERT(tObj->WrapT==GL_REPEAT);
1221 ASSERT(img->Border==0);
1222 ASSERT(img->Format==GL_RGBA);
1223 ASSERT(img->_IsPowerOfTwo);
1224
1225 for (i = 0; i < n; i++) {
1226 const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
1227 const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
1228 const GLint pos = (row << shift) | col;
1229 const GLchan *texel = ((GLchan *) img->Data) + (pos << 2); /* pos*4 */
1230 COPY_CHAN4(rgba[i], texel);
1231 }
1232 }
1233
1234
1235 /*
1236 * Given an array of texture coordinate and lambda (level of detail)
1237 * values, return an array of texture sample.
1238 */
1239 static void
1240 sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
1241 const struct gl_texture_object *tObj,
1242 GLuint n, const GLfloat texcoords[][4],
1243 const GLfloat lambda[], GLchan rgba[][4] )
1244 {
1245 const struct gl_texture_image *tImg = tObj->Image[0][tObj->BaseLevel];
1246 GLuint minStart, minEnd; /* texels with minification */
1247 GLuint magStart, magEnd; /* texels with magnification */
1248
1249 const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT)
1250 && (tObj->WrapT == GL_REPEAT)
1251 && (tImg->Border == 0 && (tImg->Width == tImg->RowStride))
1252 && (tImg->Format != GL_COLOR_INDEX)
1253 && tImg->_IsPowerOfTwo;
1254
1255 ASSERT(lambda != NULL);
1256 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
1257 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
1258
1259 if (minStart < minEnd) {
1260 /* do the minified texels */
1261 const GLuint m = minEnd - minStart;
1262 switch (tObj->MinFilter) {
1263 case GL_NEAREST:
1264 if (repeatNoBorderPOT) {
1265 switch (tImg->TexFormat->MesaFormat) {
1266 case MESA_FORMAT_RGB:
1267 case MESA_FORMAT_RGB888:
1268 /*case MESA_FORMAT_BGR888:*/
1269 opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1270 NULL, rgba + minStart);
1271 break;
1272 case MESA_FORMAT_RGBA:
1273 case MESA_FORMAT_RGBA8888:
1274 case MESA_FORMAT_ARGB8888:
1275 /*case MESA_FORMAT_ABGR8888:*/
1276 /*case MESA_FORMAT_BGRA8888:*/
1277 opt_sample_rgba_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1278 NULL, rgba + minStart);
1279 break;
1280 default:
1281 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1282 NULL, rgba + minStart );
1283 }
1284 }
1285 else {
1286 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1287 NULL, rgba + minStart);
1288 }
1289 break;
1290 case GL_LINEAR:
1291 sample_linear_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1292 NULL, rgba + minStart);
1293 break;
1294 case GL_NEAREST_MIPMAP_NEAREST:
1295 sample_2d_nearest_mipmap_nearest(ctx, tObj, m,
1296 texcoords + minStart,
1297 lambda + minStart, rgba + minStart);
1298 break;
1299 case GL_LINEAR_MIPMAP_NEAREST:
1300 sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
1301 lambda + minStart, rgba + minStart);
1302 break;
1303 case GL_NEAREST_MIPMAP_LINEAR:
1304 sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1305 lambda + minStart, rgba + minStart);
1306 break;
1307 case GL_LINEAR_MIPMAP_LINEAR:
1308 if (repeatNoBorderPOT)
1309 sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m,
1310 texcoords + minStart, lambda + minStart, rgba + minStart);
1311 else
1312 sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1313 lambda + minStart, rgba + minStart);
1314 break;
1315 default:
1316 _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1317 return;
1318 }
1319 }
1320
1321 if (magStart < magEnd) {
1322 /* do the magnified texels */
1323 const GLuint m = magEnd - magStart;
1324
1325 switch (tObj->MagFilter) {
1326 case GL_NEAREST:
1327 if (repeatNoBorderPOT) {
1328 switch (tImg->TexFormat->MesaFormat) {
1329 case MESA_FORMAT_RGB:
1330 case MESA_FORMAT_RGB888:
1331 /*case MESA_FORMAT_BGR888:*/
1332 opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1333 NULL, rgba + magStart);
1334 break;
1335 case MESA_FORMAT_RGBA:
1336 case MESA_FORMAT_RGBA8888:
1337 case MESA_FORMAT_ARGB8888:
1338 /*case MESA_FORMAT_ABGR8888:*/
1339 /*case MESA_FORMAT_BGRA8888:*/
1340 opt_sample_rgba_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1341 NULL, rgba + magStart);
1342 break;
1343 default:
1344 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1345 NULL, rgba + magStart );
1346 }
1347 }
1348 else {
1349 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1350 NULL, rgba + magStart);
1351 }
1352 break;
1353 case GL_LINEAR:
1354 sample_linear_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1355 NULL, rgba + magStart);
1356 break;
1357 default:
1358 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1359 }
1360 }
1361 }
1362
1363
1364
1365 /**********************************************************************/
1366 /* 3-D Texture Sampling Functions */
1367 /**********************************************************************/
1368
1369 /*
1370 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1371 */
1372 static void
1373 sample_3d_nearest(GLcontext *ctx,
1374 const struct gl_texture_object *tObj,
1375 const struct gl_texture_image *img,
1376 const GLfloat texcoord[4],
1377 GLchan rgba[4])
1378 {
1379 const GLint width = img->Width2; /* without border, power of two */
1380 const GLint height = img->Height2; /* without border, power of two */
1381 const GLint depth = img->Depth2; /* without border, power of two */
1382 GLint i, j, k;
1383 (void) ctx;
1384
1385 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
1386 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
1387 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, texcoord[2], depth, k);
1388
1389 if (i < 0 || i >= (GLint) img->Width ||
1390 j < 0 || j >= (GLint) img->Height ||
1391 k < 0 || k >= (GLint) img->Depth) {
1392 /* Need this test for GL_CLAMP_TO_BORDER mode */
1393 COPY_CHAN4(rgba, tObj->_BorderChan);
1394 }
1395 else {
1396 img->FetchTexelc(img, i, j, k, rgba);
1397 }
1398 }
1399
1400
1401
1402 /*
1403 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1404 */
1405 static void
1406 sample_3d_linear(GLcontext *ctx,
1407 const struct gl_texture_object *tObj,
1408 const struct gl_texture_image *img,
1409 const GLfloat texcoord[4],
1410 GLchan rgba[4])
1411 {
1412 const GLint width = img->Width2;
1413 const GLint height = img->Height2;
1414 const GLint depth = img->Depth2;
1415 GLint i0, j0, k0, i1, j1, k1;
1416 GLuint useBorderColor;
1417 GLfloat u, v, w;
1418 (void) ctx;
1419
1420 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
1421 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
1422 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, texcoord[2], w, depth, k0, k1);
1423
1424 useBorderColor = 0;
1425 if (img->Border) {
1426 i0 += img->Border;
1427 i1 += img->Border;
1428 j0 += img->Border;
1429 j1 += img->Border;
1430 k0 += img->Border;
1431 k1 += img->Border;
1432 }
1433 else {
1434 /* check if sampling texture border color */
1435 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1436 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1437 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1438 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1439 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
1440 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
1441 }
1442
1443 {
1444 const GLfloat a = FRAC(u);
1445 const GLfloat b = FRAC(v);
1446 const GLfloat c = FRAC(w);
1447
1448 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
1449 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1450 GLfloat w000 = (1.0F-a) * (1.0F-b) * (1.0F-c);
1451 GLfloat w100 = a * (1.0F-b) * (1.0F-c);
1452 GLfloat w010 = (1.0F-a) * b * (1.0F-c);
1453 GLfloat w110 = a * b * (1.0F-c);
1454 GLfloat w001 = (1.0F-a) * (1.0F-b) * c ;
1455 GLfloat w101 = a * (1.0F-b) * c ;
1456 GLfloat w011 = (1.0F-a) * b * c ;
1457 GLfloat w111 = a * b * c ;
1458 #else /* CHAN_BITS == 8 */
1459 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1460 GLint w000 = IROUND_POS((1.0F-a) * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1461 GLint w100 = IROUND_POS( a * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1462 GLint w010 = IROUND_POS((1.0F-a) * b * (1.0F-c) * WEIGHT_SCALE);
1463 GLint w110 = IROUND_POS( a * b * (1.0F-c) * WEIGHT_SCALE);
1464 GLint w001 = IROUND_POS((1.0F-a) * (1.0F-b) * c * WEIGHT_SCALE);
1465 GLint w101 = IROUND_POS( a * (1.0F-b) * c * WEIGHT_SCALE);
1466 GLint w011 = IROUND_POS((1.0F-a) * b * c * WEIGHT_SCALE);
1467 GLint w111 = IROUND_POS( a * b * c * WEIGHT_SCALE);
1468 #endif
1469
1470 GLchan t000[4], t010[4], t001[4], t011[4];
1471 GLchan t100[4], t110[4], t101[4], t111[4];
1472
1473 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
1474 COPY_CHAN4(t000, tObj->_BorderChan);
1475 }
1476 else {
1477 img->FetchTexelc(img, i0, j0, k0, t000);
1478 }
1479 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
1480 COPY_CHAN4(t100, tObj->_BorderChan);
1481 }
1482 else {
1483 img->FetchTexelc(img, i1, j0, k0, t100);
1484 }
1485 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
1486 COPY_CHAN4(t010, tObj->_BorderChan);
1487 }
1488 else {
1489 img->FetchTexelc(img, i0, j1, k0, t010);
1490 }
1491 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
1492 COPY_CHAN4(t110, tObj->_BorderChan);
1493 }
1494 else {
1495 img->FetchTexelc(img, i1, j1, k0, t110);
1496 }
1497
1498 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
1499 COPY_CHAN4(t001, tObj->_BorderChan);
1500 }
1501 else {
1502 img->FetchTexelc(img, i0, j0, k1, t001);
1503 }
1504 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
1505 COPY_CHAN4(t101, tObj->_BorderChan);
1506 }
1507 else {
1508 img->FetchTexelc(img, i1, j0, k1, t101);
1509 }
1510 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
1511 COPY_CHAN4(t011, tObj->_BorderChan);
1512 }
1513 else {
1514 img->FetchTexelc(img, i0, j1, k1, t011);
1515 }
1516 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
1517 COPY_CHAN4(t111, tObj->_BorderChan);
1518 }
1519 else {
1520 img->FetchTexelc(img, i1, j1, k1, t111);
1521 }
1522
1523 #if CHAN_TYPE == GL_FLOAT
1524 rgba[0] = w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1525 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0];
1526 rgba[1] = w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1527 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1];
1528 rgba[2] = w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1529 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2];
1530 rgba[3] = w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1531 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3];
1532 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
1533 rgba[0] = (GLchan) (w000*t000[0] + w010*t010[0] +
1534 w001*t001[0] + w011*t011[0] +
1535 w100*t100[0] + w110*t110[0] +
1536 w101*t101[0] + w111*t111[0] + 0.5);
1537 rgba[1] = (GLchan) (w000*t000[1] + w010*t010[1] +
1538 w001*t001[1] + w011*t011[1] +
1539 w100*t100[1] + w110*t110[1] +
1540 w101*t101[1] + w111*t111[1] + 0.5);
1541 rgba[2] = (GLchan) (w000*t000[2] + w010*t010[2] +
1542 w001*t001[2] + w011*t011[2] +
1543 w100*t100[2] + w110*t110[2] +
1544 w101*t101[2] + w111*t111[2] + 0.5);
1545 rgba[3] = (GLchan) (w000*t000[3] + w010*t010[3] +
1546 w001*t001[3] + w011*t011[3] +
1547 w100*t100[3] + w110*t110[3] +
1548 w101*t101[3] + w111*t111[3] + 0.5);
1549 #else /* CHAN_BITS == 8 */
1550 rgba[0] = (GLchan) (
1551 (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1552 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] )
1553 >> WEIGHT_SHIFT);
1554 rgba[1] = (GLchan) (
1555 (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1556 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
1557 >> WEIGHT_SHIFT);
1558 rgba[2] = (GLchan) (
1559 (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1560 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
1561 >> WEIGHT_SHIFT);
1562 rgba[3] = (GLchan) (
1563 (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1564 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
1565 >> WEIGHT_SHIFT);
1566 #endif
1567
1568 }
1569 }
1570
1571
1572
1573 static void
1574 sample_3d_nearest_mipmap_nearest(GLcontext *ctx,
1575 const struct gl_texture_object *tObj,
1576 GLuint n, const GLfloat texcoord[][4],
1577 const GLfloat lambda[], GLchan rgba[][4] )
1578 {
1579 GLuint i;
1580 for (i = 0; i < n; i++) {
1581 GLint level;
1582 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1583 sample_3d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1584 }
1585 }
1586
1587
1588 static void
1589 sample_3d_linear_mipmap_nearest(GLcontext *ctx,
1590 const struct gl_texture_object *tObj,
1591 GLuint n, const GLfloat texcoord[][4],
1592 const GLfloat lambda[], GLchan rgba[][4])
1593 {
1594 GLuint i;
1595 ASSERT(lambda != NULL);
1596 for (i = 0; i < n; i++) {
1597 GLint level;
1598 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1599 sample_3d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
1600 }
1601 }
1602
1603
1604 static void
1605 sample_3d_nearest_mipmap_linear(GLcontext *ctx,
1606 const struct gl_texture_object *tObj,
1607 GLuint n, const GLfloat texcoord[][4],
1608 const GLfloat lambda[], GLchan rgba[][4])
1609 {
1610 GLuint i;
1611 ASSERT(lambda != NULL);
1612 for (i = 0; i < n; i++) {
1613 GLint level;
1614 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1615 if (level >= tObj->_MaxLevel) {
1616 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1617 texcoord[i], rgba[i]);
1618 }
1619 else {
1620 GLchan t0[4], t1[4]; /* texels */
1621 const GLfloat f = FRAC(lambda[i]);
1622 sample_3d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1623 sample_3d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1624 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1625 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1626 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1627 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1628 }
1629 }
1630 }
1631
1632
1633 static void
1634 sample_3d_linear_mipmap_linear(GLcontext *ctx,
1635 const struct gl_texture_object *tObj,
1636 GLuint n, const GLfloat texcoord[][4],
1637 const GLfloat lambda[], GLchan rgba[][4])
1638 {
1639 GLuint i;
1640 ASSERT(lambda != NULL);
1641 for (i = 0; i < n; i++) {
1642 GLint level;
1643 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1644 if (level >= tObj->_MaxLevel) {
1645 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
1646 texcoord[i], rgba[i]);
1647 }
1648 else {
1649 GLchan t0[4], t1[4]; /* texels */
1650 const GLfloat f = FRAC(lambda[i]);
1651 sample_3d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
1652 sample_3d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
1653 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1654 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1655 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1656 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1657 }
1658 }
1659 }
1660
1661
1662 static void
1663 sample_nearest_3d(GLcontext *ctx, GLuint texUnit,
1664 const struct gl_texture_object *tObj, GLuint n,
1665 const GLfloat texcoords[][4], const GLfloat lambda[],
1666 GLchan rgba[][4])
1667 {
1668 GLuint i;
1669 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1670 (void) texUnit;
1671 (void) lambda;
1672 for (i=0;i<n;i++) {
1673 sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
1674 }
1675 }
1676
1677
1678
1679 static void
1680 sample_linear_3d( GLcontext *ctx, GLuint texUnit,
1681 const struct gl_texture_object *tObj, GLuint n,
1682 const GLfloat texcoords[][4],
1683 const GLfloat lambda[], GLchan rgba[][4] )
1684 {
1685 GLuint i;
1686 struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
1687 (void) texUnit;
1688 (void) lambda;
1689 for (i=0;i<n;i++) {
1690 sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
1691 }
1692 }
1693
1694
1695 /*
1696 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1697 * return a texture sample.
1698 */
1699 static void
1700 sample_lambda_3d( GLcontext *ctx, GLuint texUnit,
1701 const struct gl_texture_object *tObj, GLuint n,
1702 const GLfloat texcoords[][4], const GLfloat lambda[],
1703 GLchan rgba[][4] )
1704 {
1705 GLuint minStart, minEnd; /* texels with minification */
1706 GLuint magStart, magEnd; /* texels with magnification */
1707 GLuint i;
1708
1709 ASSERT(lambda != NULL);
1710 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
1711 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
1712
1713 if (minStart < minEnd) {
1714 /* do the minified texels */
1715 GLuint m = minEnd - minStart;
1716 switch (tObj->MinFilter) {
1717 case GL_NEAREST:
1718 for (i = minStart; i < minEnd; i++)
1719 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1720 texcoords[i], rgba[i]);
1721 break;
1722 case GL_LINEAR:
1723 for (i = minStart; i < minEnd; i++)
1724 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1725 texcoords[i], rgba[i]);
1726 break;
1727 case GL_NEAREST_MIPMAP_NEAREST:
1728 sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
1729 lambda + minStart, rgba + minStart);
1730 break;
1731 case GL_LINEAR_MIPMAP_NEAREST:
1732 sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
1733 lambda + minStart, rgba + minStart);
1734 break;
1735 case GL_NEAREST_MIPMAP_LINEAR:
1736 sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1737 lambda + minStart, rgba + minStart);
1738 break;
1739 case GL_LINEAR_MIPMAP_LINEAR:
1740 sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1741 lambda + minStart, rgba + minStart);
1742 break;
1743 default:
1744 _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
1745 return;
1746 }
1747 }
1748
1749 if (magStart < magEnd) {
1750 /* do the magnified texels */
1751 switch (tObj->MagFilter) {
1752 case GL_NEAREST:
1753 for (i = magStart; i < magEnd; i++)
1754 sample_3d_nearest(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1755 texcoords[i], rgba[i]);
1756 break;
1757 case GL_LINEAR:
1758 for (i = magStart; i < magEnd; i++)
1759 sample_3d_linear(ctx, tObj, tObj->Image[0][tObj->BaseLevel],
1760 texcoords[i], rgba[i]);
1761 break;
1762 default:
1763 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
1764 return;
1765 }
1766 }
1767 }
1768
1769
1770 /**********************************************************************/
1771 /* Texture Cube Map Sampling Functions */
1772 /**********************************************************************/
1773
1774 /*
1775 * Choose one of six sides of a texture cube map given the texture
1776 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1777 * images.
1778 */
1779 static const struct gl_texture_image **
1780 choose_cube_face(const struct gl_texture_object *texObj,
1781 const GLfloat texcoord[4], GLfloat newCoord[4])
1782 {
1783 /*
1784 major axis
1785 direction target sc tc ma
1786 ---------- ------------------------------- --- --- ---
1787 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1788 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1789 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1790 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1791 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1792 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1793 */
1794 const GLfloat rx = texcoord[0];
1795 const GLfloat ry = texcoord[1];
1796 const GLfloat rz = texcoord[2];
1797 const struct gl_texture_image **imgArray;
1798 const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
1799 GLfloat sc, tc, ma;
1800
1801 if (arx > ary && arx > arz) {
1802 if (rx >= 0.0F) {
1803 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_POS_X];
1804 sc = -rz;
1805 tc = -ry;
1806 ma = arx;
1807 }
1808 else {
1809 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_NEG_X];
1810 sc = rz;
1811 tc = -ry;
1812 ma = arx;
1813 }
1814 }
1815 else if (ary > arx && ary > arz) {
1816 if (ry >= 0.0F) {
1817 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_POS_Y];
1818 sc = rx;
1819 tc = rz;
1820 ma = ary;
1821 }
1822 else {
1823 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_NEG_Y];
1824 sc = rx;
1825 tc = -rz;
1826 ma = ary;
1827 }
1828 }
1829 else {
1830 if (rz > 0.0F) {
1831 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_POS_Z];
1832 sc = rx;
1833 tc = -ry;
1834 ma = arz;
1835 }
1836 else {
1837 imgArray = (const struct gl_texture_image **) texObj->Image[FACE_NEG_Z];
1838 sc = -rx;
1839 tc = -ry;
1840 ma = arz;
1841 }
1842 }
1843
1844 newCoord[0] = ( sc / ma + 1.0F ) * 0.5F;
1845 newCoord[1] = ( tc / ma + 1.0F ) * 0.5F;
1846 return imgArray;
1847 }
1848
1849
1850 static void
1851 sample_nearest_cube(GLcontext *ctx, GLuint texUnit,
1852 const struct gl_texture_object *tObj, GLuint n,
1853 const GLfloat texcoords[][4], const GLfloat lambda[],
1854 GLchan rgba[][4])
1855 {
1856 GLuint i;
1857 (void) texUnit;
1858 (void) lambda;
1859 for (i = 0; i < n; i++) {
1860 const struct gl_texture_image **images;
1861 GLfloat newCoord[4];
1862 images = choose_cube_face(tObj, texcoords[i], newCoord);
1863 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1864 newCoord, rgba[i]);
1865 }
1866 }
1867
1868
1869 static void
1870 sample_linear_cube(GLcontext *ctx, GLuint texUnit,
1871 const struct gl_texture_object *tObj, GLuint n,
1872 const GLfloat texcoords[][4],
1873 const GLfloat lambda[], GLchan rgba[][4])
1874 {
1875 GLuint i;
1876 (void) texUnit;
1877 (void) lambda;
1878 for (i = 0; i < n; i++) {
1879 const struct gl_texture_image **images;
1880 GLfloat newCoord[4];
1881 images = choose_cube_face(tObj, texcoords[i], newCoord);
1882 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1883 newCoord, rgba[i]);
1884 }
1885 }
1886
1887
1888 static void
1889 sample_cube_nearest_mipmap_nearest(GLcontext *ctx, GLuint texUnit,
1890 const struct gl_texture_object *tObj,
1891 GLuint n, const GLfloat texcoord[][4],
1892 const GLfloat lambda[], GLchan rgba[][4])
1893 {
1894 GLuint i;
1895 (void) texUnit;
1896 ASSERT(lambda != NULL);
1897 for (i = 0; i < n; i++) {
1898 const struct gl_texture_image **images;
1899 GLfloat newCoord[4];
1900 GLint level;
1901 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1902 images = choose_cube_face(tObj, texcoord[i], newCoord);
1903 sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]);
1904 }
1905 }
1906
1907
1908 static void
1909 sample_cube_linear_mipmap_nearest(GLcontext *ctx, GLuint texUnit,
1910 const struct gl_texture_object *tObj,
1911 GLuint n, const GLfloat texcoord[][4],
1912 const GLfloat lambda[], GLchan rgba[][4])
1913 {
1914 GLuint i;
1915 (void) texUnit;
1916 ASSERT(lambda != NULL);
1917 for (i = 0; i < n; i++) {
1918 const struct gl_texture_image **images;
1919 GLfloat newCoord[4];
1920 GLint level;
1921 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1922 images = choose_cube_face(tObj, texcoord[i], newCoord);
1923 sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]);
1924 }
1925 }
1926
1927
1928 static void
1929 sample_cube_nearest_mipmap_linear(GLcontext *ctx, GLuint texUnit,
1930 const struct gl_texture_object *tObj,
1931 GLuint n, const GLfloat texcoord[][4],
1932 const GLfloat lambda[], GLchan rgba[][4])
1933 {
1934 GLuint i;
1935 (void) texUnit;
1936 ASSERT(lambda != NULL);
1937 for (i = 0; i < n; i++) {
1938 const struct gl_texture_image **images;
1939 GLfloat newCoord[4];
1940 GLint level;
1941 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1942 images = choose_cube_face(tObj, texcoord[i], newCoord);
1943 if (level >= tObj->_MaxLevel) {
1944 sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel],
1945 newCoord, rgba[i]);
1946 }
1947 else {
1948 GLchan t0[4], t1[4]; /* texels */
1949 const GLfloat f = FRAC(lambda[i]);
1950 sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0);
1951 sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1);
1952 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1953 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1954 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1955 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1956 }
1957 }
1958 }
1959
1960
1961 static void
1962 sample_cube_linear_mipmap_linear(GLcontext *ctx, GLuint texUnit,
1963 const struct gl_texture_object *tObj,
1964 GLuint n, const GLfloat texcoord[][4],
1965 const GLfloat lambda[], GLchan rgba[][4])
1966 {
1967 GLuint i;
1968 (void) texUnit;
1969 ASSERT(lambda != NULL);
1970 for (i = 0; i < n; i++) {
1971 const struct gl_texture_image **images;
1972 GLfloat newCoord[4];
1973 GLint level;
1974 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1975 images = choose_cube_face(tObj, texcoord[i], newCoord);
1976 if (level >= tObj->_MaxLevel) {
1977 sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel],
1978 newCoord, rgba[i]);
1979 }
1980 else {
1981 GLchan t0[4], t1[4];
1982 const GLfloat f = FRAC(lambda[i]);
1983 sample_2d_linear(ctx, tObj, images[level ], newCoord, t0);
1984 sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1);
1985 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1986 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1987 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1988 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1989 }
1990 }
1991 }
1992
1993
1994 static void
1995 sample_lambda_cube( GLcontext *ctx, GLuint texUnit,
1996 const struct gl_texture_object *tObj, GLuint n,
1997 const GLfloat texcoords[][4], const GLfloat lambda[],
1998 GLchan rgba[][4])
1999 {
2000 GLuint minStart, minEnd; /* texels with minification */
2001 GLuint magStart, magEnd; /* texels with magnification */
2002
2003 ASSERT(lambda != NULL);
2004 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
2005 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
2006
2007 if (minStart < minEnd) {
2008 /* do the minified texels */
2009 const GLuint m = minEnd - minStart;
2010 switch (tObj->MinFilter) {
2011 case GL_NEAREST:
2012 sample_nearest_cube(ctx, texUnit, tObj, m, texcoords + minStart,
2013 lambda + minStart, rgba + minStart);
2014 break;
2015 case GL_LINEAR:
2016 sample_linear_cube(ctx, texUnit, tObj, m, texcoords + minStart,
2017 lambda + minStart, rgba + minStart);
2018 break;
2019 case GL_NEAREST_MIPMAP_NEAREST:
2020 sample_cube_nearest_mipmap_nearest(ctx, texUnit, tObj, m,
2021 texcoords + minStart,
2022 lambda + minStart, rgba + minStart);
2023 break;
2024 case GL_LINEAR_MIPMAP_NEAREST:
2025 sample_cube_linear_mipmap_nearest(ctx, texUnit, tObj, m,
2026 texcoords + minStart,
2027 lambda + minStart, rgba + minStart);
2028 break;
2029 case GL_NEAREST_MIPMAP_LINEAR:
2030 sample_cube_nearest_mipmap_linear(ctx, texUnit, tObj, m,
2031 texcoords + minStart,
2032 lambda + minStart, rgba + minStart);
2033 break;
2034 case GL_LINEAR_MIPMAP_LINEAR:
2035 sample_cube_linear_mipmap_linear(ctx, texUnit, tObj, m,
2036 texcoords + minStart,
2037 lambda + minStart, rgba + minStart);
2038 break;
2039 default:
2040 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2041 }
2042 }
2043
2044 if (magStart < magEnd) {
2045 /* do the magnified texels */
2046 const GLuint m = magEnd - magStart;
2047 switch (tObj->MagFilter) {
2048 case GL_NEAREST:
2049 sample_nearest_cube(ctx, texUnit, tObj, m, texcoords + magStart,
2050 lambda + magStart, rgba + magStart);
2051 break;
2052 case GL_LINEAR:
2053 sample_linear_cube(ctx, texUnit, tObj, m, texcoords + magStart,
2054 lambda + magStart, rgba + magStart);
2055 break;
2056 default:
2057 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2058 }
2059 }
2060 }
2061
2062
2063 /**********************************************************************/
2064 /* Texture Rectangle Sampling Functions */
2065 /**********************************************************************/
2066
2067 static void
2068 sample_nearest_rect(GLcontext *ctx, GLuint texUnit,
2069 const struct gl_texture_object *tObj, GLuint n,
2070 const GLfloat texcoords[][4], const GLfloat lambda[],
2071 GLchan rgba[][4])
2072 {
2073 const struct gl_texture_image *img = tObj->Image[0][0];
2074 const GLfloat width = (GLfloat) img->Width;
2075 const GLfloat height = (GLfloat) img->Height;
2076 const GLint width_minus_1 = img->Width - 1;
2077 const GLint height_minus_1 = img->Height - 1;
2078 GLuint i;
2079
2080 (void) ctx;
2081 (void) texUnit;
2082 (void) lambda;
2083
2084 ASSERT(tObj->WrapS == GL_CLAMP ||
2085 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2086 tObj->WrapS == GL_CLAMP_TO_BORDER);
2087 ASSERT(tObj->WrapT == GL_CLAMP ||
2088 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2089 tObj->WrapT == GL_CLAMP_TO_BORDER);
2090 ASSERT(img->Format != GL_COLOR_INDEX);
2091
2092 /* XXX move Wrap mode tests outside of loops for common cases */
2093 for (i = 0; i < n; i++) {
2094 GLint row, col;
2095 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2096 if (tObj->WrapS == GL_CLAMP) {
2097 col = IFLOOR( CLAMP(texcoords[i][0], 0.0F, width - 1) );
2098 }
2099 else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
2100 col = IFLOOR( CLAMP(texcoords[i][0], 0.5F, width - 0.5F) );
2101 }
2102 else {
2103 col = IFLOOR( CLAMP(texcoords[i][0], -0.5F, width + 0.5F) );
2104 }
2105 if (tObj->WrapT == GL_CLAMP) {
2106 row = IFLOOR( CLAMP(texcoords[i][1], 0.0F, height - 1) );
2107 }
2108 else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
2109 row = IFLOOR( CLAMP(texcoords[i][1], 0.5F, height - 0.5F) );
2110 }
2111 else {
2112 row = IFLOOR( CLAMP(texcoords[i][1], -0.5F, height + 0.5F) );
2113 }
2114
2115 if (col < 0 || col > width_minus_1 || row < 0 || row > height_minus_1)
2116 COPY_CHAN4(rgba[i], tObj->_BorderChan);
2117 else
2118 img->FetchTexelc(img, col, row, 0, rgba[i]);
2119 }
2120 }
2121
2122
2123 static void
2124 sample_linear_rect(GLcontext *ctx, GLuint texUnit,
2125 const struct gl_texture_object *tObj, GLuint n,
2126 const GLfloat texcoords[][4],
2127 const GLfloat lambda[], GLchan rgba[][4])
2128 {
2129 const struct gl_texture_image *img = tObj->Image[0][0];
2130 const GLfloat width = (GLfloat) img->Width;
2131 const GLfloat height = (GLfloat) img->Height;
2132 const GLint width_minus_1 = img->Width - 1;
2133 const GLint height_minus_1 = img->Height - 1;
2134 GLuint i;
2135
2136 (void) ctx;
2137 (void) texUnit;
2138 (void) lambda;
2139
2140 ASSERT(tObj->WrapS == GL_CLAMP ||
2141 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2142 tObj->WrapS == GL_CLAMP_TO_BORDER);
2143 ASSERT(tObj->WrapT == GL_CLAMP ||
2144 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2145 tObj->WrapT == GL_CLAMP_TO_BORDER);
2146 ASSERT(img->Format != GL_COLOR_INDEX);
2147
2148 /* XXX lots of opportunity for optimization in this loop */
2149 for (i = 0; i < n; i++) {
2150 GLfloat frow, fcol;
2151 GLint i0, j0, i1, j1;
2152 GLchan t00[4], t01[4], t10[4], t11[4];
2153 GLfloat a, b, w00, w01, w10, w11;
2154 GLuint useBorderColor = 0;
2155
2156 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2157 if (tObj->WrapS == GL_CLAMP) {
2158 /* Not exactly what the spec says, but it matches NVIDIA output */
2159 fcol = CLAMP(texcoords[i][0] - 0.5F, 0.0, width_minus_1);
2160 i0 = IFLOOR(fcol);
2161 i1 = i0 + 1;
2162 }
2163 else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
2164 fcol = CLAMP(texcoords[i][0], 0.5F, width - 0.5F);
2165 fcol -= 0.5F;
2166 i0 = IFLOOR(fcol);
2167 i1 = i0 + 1;
2168 if (i1 > width_minus_1)
2169 i1 = width_minus_1;
2170 }
2171 else {
2172 ASSERT(tObj->WrapS == GL_CLAMP_TO_BORDER);
2173 fcol = CLAMP(texcoords[i][0], -0.5F, width + 0.5F);
2174 fcol -= 0.5F;
2175 i0 = IFLOOR(fcol);
2176 i1 = i0 + 1;
2177 }
2178
2179 if (tObj->WrapT == GL_CLAMP) {
2180 /* Not exactly what the spec says, but it matches NVIDIA output */
2181 frow = CLAMP(texcoords[i][1] - 0.5F, 0.0, width_minus_1);
2182 j0 = IFLOOR(frow);
2183 j1 = j0 + 1;
2184 }
2185 else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
2186 frow = CLAMP(texcoords[i][1], 0.5F, height - 0.5F);
2187 frow -= 0.5F;
2188 j0 = IFLOOR(frow);
2189 j1 = j0 + 1;
2190 if (j1 > height_minus_1)
2191 j1 = height_minus_1;
2192 }
2193 else {
2194 ASSERT(tObj->WrapT == GL_CLAMP_TO_BORDER);
2195 frow = CLAMP(texcoords[i][1], -0.5F, height + 0.5F);
2196 frow -= 0.5F;
2197 j0 = IFLOOR(frow);
2198 j1 = j0 + 1;
2199 }
2200
2201 /* compute integer rows/columns */
2202 if (i0 < 0 || i0 > width_minus_1) useBorderColor |= I0BIT;
2203 if (i1 < 0 || i1 > width_minus_1) useBorderColor |= I1BIT;
2204 if (j0 < 0 || j0 > height_minus_1) useBorderColor |= J0BIT;
2205 if (j1 < 0 || j1 > height_minus_1) useBorderColor |= J1BIT;
2206
2207 /* get four texel samples */
2208 if (useBorderColor & (I0BIT | J0BIT))
2209 COPY_CHAN4(t00, tObj->_BorderChan);
2210 else
2211 img->FetchTexelc(img, i0, j0, 0, t00);
2212
2213 if (useBorderColor & (I1BIT | J0BIT))
2214 COPY_CHAN4(t10, tObj->_BorderChan);
2215 else
2216 img->FetchTexelc(img, i1, j0, 0, t10);
2217
2218 if (useBorderColor & (I0BIT | J1BIT))
2219 COPY_CHAN4(t01, tObj->_BorderChan);
2220 else
2221 img->FetchTexelc(img, i0, j1, 0, t01);
2222
2223 if (useBorderColor & (I1BIT | J1BIT))
2224 COPY_CHAN4(t11, tObj->_BorderChan);
2225 else
2226 img->FetchTexelc(img, i1, j1, 0, t11);
2227
2228 /* compute sample weights */
2229 a = FRAC(fcol);
2230 b = FRAC(frow);
2231 w00 = (1.0F-a) * (1.0F-b);
2232 w10 = a * (1.0F-b);
2233 w01 = (1.0F-a) * b ;
2234 w11 = a * b ;
2235
2236 /* compute weighted average of samples */
2237 rgba[i][0] =
2238 (GLchan) (w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]);
2239 rgba[i][1] =
2240 (GLchan) (w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]);
2241 rgba[i][2] =
2242 (GLchan) (w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]);
2243 rgba[i][3] =
2244 (GLchan) (w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]);
2245 }
2246 }
2247
2248
2249 static void
2250 sample_lambda_rect( GLcontext *ctx, GLuint texUnit,
2251 const struct gl_texture_object *tObj, GLuint n,
2252 const GLfloat texcoords[][4], const GLfloat lambda[],
2253 GLchan rgba[][4])
2254 {
2255 GLuint minStart, minEnd, magStart, magEnd;
2256
2257 /* We only need lambda to decide between minification and magnification.
2258 * There is no mipmapping with rectangular textures.
2259 */
2260 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
2261 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
2262
2263 if (minStart < minEnd) {
2264 if (tObj->MinFilter == GL_NEAREST) {
2265 sample_nearest_rect( ctx, texUnit, tObj, minEnd - minStart,
2266 texcoords + minStart, NULL, rgba + minStart);
2267 }
2268 else {
2269 sample_linear_rect( ctx, texUnit, tObj, minEnd - minStart,
2270 texcoords + minStart, NULL, rgba + minStart);
2271 }
2272 }
2273 if (magStart < magEnd) {
2274 if (tObj->MagFilter == GL_NEAREST) {
2275 sample_nearest_rect( ctx, texUnit, tObj, magEnd - magStart,
2276 texcoords + magStart, NULL, rgba + magStart);
2277 }
2278 else {
2279 sample_linear_rect( ctx, texUnit, tObj, magEnd - magStart,
2280 texcoords + magStart, NULL, rgba + magStart);
2281 }
2282 }
2283 }
2284
2285
2286
2287 /*
2288 * Sample a shadow/depth texture.
2289 */
2290 static void
2291 sample_depth_texture( GLcontext *ctx, GLuint unit,
2292 const struct gl_texture_object *tObj, GLuint n,
2293 const GLfloat texcoords[][4], const GLfloat lambda[],
2294 GLchan texel[][4] )
2295 {
2296 const GLint baseLevel = tObj->BaseLevel;
2297 const struct gl_texture_image *texImage = tObj->Image[0][baseLevel];
2298 const GLuint width = texImage->Width;
2299 const GLuint height = texImage->Height;
2300 GLchan ambient;
2301 GLenum function;
2302 GLchan result;
2303
2304 (void) lambda;
2305 (void) unit;
2306
2307 ASSERT(tObj->Image[0][tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
2308 ASSERT(tObj->Target == GL_TEXTURE_1D ||
2309 tObj->Target == GL_TEXTURE_2D ||
2310 tObj->Target == GL_TEXTURE_RECTANGLE_NV);
2311
2312 UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
2313
2314 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2315
2316 /* XXX this could be precomputed and saved in the texture object */
2317 if (tObj->CompareFlag) {
2318 /* GL_SGIX_shadow */
2319 if (tObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2320 function = GL_LEQUAL;
2321 }
2322 else {
2323 ASSERT(tObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
2324 function = GL_GEQUAL;
2325 }
2326 }
2327 else if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
2328 /* GL_ARB_shadow */
2329 function = tObj->CompareFunc;
2330 }
2331 else {
2332 function = GL_NONE; /* pass depth through as grayscale */
2333 }
2334
2335 if (tObj->MagFilter == GL_NEAREST) {
2336 GLuint i;
2337 for (i = 0; i < n; i++) {
2338 GLfloat depthSample;
2339 GLint col, row;
2340 /* XXX fix for texture rectangle! */
2341 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
2342 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
2343 texImage->FetchTexelf(texImage, col, row, 0, &depthSample);
2344
2345 switch (function) {
2346 case GL_LEQUAL:
2347 result = (texcoords[i][2] <= depthSample) ? CHAN_MAX : ambient;
2348 break;
2349 case GL_GEQUAL:
2350 result = (texcoords[i][2] >= depthSample) ? CHAN_MAX : ambient;
2351 break;
2352 case GL_LESS:
2353 result = (texcoords[i][2] < depthSample) ? CHAN_MAX : ambient;
2354 break;
2355 case GL_GREATER:
2356 result = (texcoords[i][2] > depthSample) ? CHAN_MAX : ambient;
2357 break;
2358 case GL_EQUAL:
2359 result = (texcoords[i][2] == depthSample) ? CHAN_MAX : ambient;
2360 break;
2361 case GL_NOTEQUAL:
2362 result = (texcoords[i][2] != depthSample) ? CHAN_MAX : ambient;
2363 break;
2364 case GL_ALWAYS:
2365 result = CHAN_MAX;
2366 break;
2367 case GL_NEVER:
2368 result = ambient;
2369 break;
2370 case GL_NONE:
2371 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
2372 break;
2373 default:
2374 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
2375 return;
2376 }
2377
2378 switch (tObj->DepthMode) {
2379 case GL_LUMINANCE:
2380 texel[i][RCOMP] = result;
2381 texel[i][GCOMP] = result;
2382 texel[i][BCOMP] = result;
2383 texel[i][ACOMP] = CHAN_MAX;
2384 break;
2385 case GL_INTENSITY:
2386 texel[i][RCOMP] = result;
2387 texel[i][GCOMP] = result;
2388 texel[i][BCOMP] = result;
2389 texel[i][ACOMP] = result;
2390 break;
2391 case GL_ALPHA:
2392 texel[i][RCOMP] = 0;
2393 texel[i][GCOMP] = 0;
2394 texel[i][BCOMP] = 0;
2395 texel[i][ACOMP] = result;
2396 break;
2397 default:
2398 _mesa_problem(ctx, "Bad depth texture mode");
2399 }
2400 }
2401 }
2402 else {
2403 GLuint i;
2404 ASSERT(tObj->MagFilter == GL_LINEAR);
2405 for (i = 0; i < n; i++) {
2406 GLfloat depth00, depth01, depth10, depth11;
2407 GLint i0, i1, j0, j1;
2408 GLfloat u, v;
2409 GLuint useBorderTexel;
2410
2411 /* XXX fix for texture rectangle! */
2412 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
2413 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
2414
2415 useBorderTexel = 0;
2416 if (texImage->Border) {
2417 i0 += texImage->Border;
2418 i1 += texImage->Border;
2419 j0 += texImage->Border;
2420 j1 += texImage->Border;
2421 }
2422 else {
2423 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
2424 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
2425 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
2426 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
2427 }
2428
2429 /* get four depth samples from the texture */
2430 if (useBorderTexel & (I0BIT | J0BIT)) {
2431 depth00 = 1.0;
2432 }
2433 else {
2434 texImage->FetchTexelf(texImage, i0, j0, 0, &depth00);
2435 }
2436 if (useBorderTexel & (I1BIT | J0BIT)) {
2437 depth10 = 1.0;
2438 }
2439 else {
2440 texImage->FetchTexelf(texImage, i1, j0, 0, &depth10);
2441 }
2442 if (useBorderTexel & (I0BIT | J1BIT)) {
2443 depth01 = 1.0;
2444 }
2445 else {
2446 texImage->FetchTexelf(texImage, i0, j1, 0, &depth01);
2447 }
2448 if (useBorderTexel & (I1BIT | J1BIT)) {
2449 depth11 = 1.0;
2450 }
2451 else {
2452 texImage->FetchTexelf(texImage, i1, j1, 0, &depth11);
2453 }
2454
2455 if (0) {
2456 /* compute a single weighted depth sample and do one comparison */
2457 const GLfloat a = FRAC(u + 1.0F);
2458 const GLfloat b = FRAC(v + 1.0F);
2459 const GLfloat w00 = (1.0F - a) * (1.0F - b);
2460 const GLfloat w10 = ( a) * (1.0F - b);
2461 const GLfloat w01 = (1.0F - a) * ( b);
2462 const GLfloat w11 = ( a) * ( b);
2463 const GLfloat depthSample = w00 * depth00 + w10 * depth10
2464 + w01 * depth01 + w11 * depth11;
2465 if ((depthSample <= texcoords[i][2] && function == GL_LEQUAL) ||
2466 (depthSample >= texcoords[i][2] && function == GL_GEQUAL)) {
2467 result = ambient;
2468 }
2469 else {
2470 result = CHAN_MAX;
2471 }
2472 }
2473 else {
2474 /* Do four depth/R comparisons and compute a weighted result.
2475 * If this touches on somebody's I.P., I'll remove this code
2476 * upon request.
2477 */
2478 const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
2479 GLfloat luminance = CHAN_MAXF;
2480
2481 switch (function) {
2482 case GL_LEQUAL:
2483 if (depth00 <= texcoords[i][2]) luminance -= d;
2484 if (depth01 <= texcoords[i][2]) luminance -= d;
2485 if (depth10 <= texcoords[i][2]) luminance -= d;
2486 if (depth11 <= texcoords[i][2]) luminance -= d;
2487 result = (GLchan) luminance;
2488 break;
2489 case GL_GEQUAL:
2490 if (depth00 >= texcoords[i][2]) luminance -= d;
2491 if (depth01 >= texcoords[i][2]) luminance -= d;
2492 if (depth10 >= texcoords[i][2]) luminance -= d;
2493 if (depth11 >= texcoords[i][2]) luminance -= d;
2494 result = (GLchan) luminance;
2495 break;
2496 case GL_LESS:
2497 if (depth00 < texcoords[i][2]) luminance -= d;
2498 if (depth01 < texcoords[i][2]) luminance -= d;
2499 if (depth10 < texcoords[i][2]) luminance -= d;
2500 if (depth11 < texcoords[i][2]) luminance -= d;
2501 result = (GLchan) luminance;
2502 break;
2503 case GL_GREATER:
2504 if (depth00 > texcoords[i][2]) luminance -= d;
2505 if (depth01 > texcoords[i][2]) luminance -= d;
2506 if (depth10 > texcoords[i][2]) luminance -= d;
2507 if (depth11 > texcoords[i][2]) luminance -= d;
2508 result = (GLchan) luminance;
2509 break;
2510 case GL_EQUAL:
2511 if (depth00 == texcoords[i][2]) luminance -= d;
2512 if (depth01 == texcoords[i][2]) luminance -= d;
2513 if (depth10 == texcoords[i][2]) luminance -= d;
2514 if (depth11 == texcoords[i][2]) luminance -= d;
2515 result = (GLchan) luminance;
2516 break;
2517 case GL_NOTEQUAL:
2518 if (depth00 != texcoords[i][2]) luminance -= d;
2519 if (depth01 != texcoords[i][2]) luminance -= d;
2520 if (depth10 != texcoords[i][2]) luminance -= d;
2521 if (depth11 != texcoords[i][2]) luminance -= d;
2522 result = (GLchan) luminance;
2523 break;
2524 case GL_ALWAYS:
2525 result = 0;
2526 break;
2527 case GL_NEVER:
2528 result = CHAN_MAX;
2529 break;
2530 case GL_NONE:
2531 /* ordinary bilinear filtering */
2532 {
2533 const GLfloat a = FRAC(u + 1.0F);
2534 const GLfloat b = FRAC(v + 1.0F);
2535 const GLfloat w00 = (1.0F - a) * (1.0F - b);
2536 const GLfloat w10 = ( a) * (1.0F - b);
2537 const GLfloat w01 = (1.0F - a) * ( b);
2538 const GLfloat w11 = ( a) * ( b);
2539 const GLfloat depthSample = w00 * depth00 + w10 * depth10
2540 + w01 * depth01 + w11 * depth11;
2541 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
2542 }
2543 break;
2544 default:
2545 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
2546 return;
2547 }
2548 }
2549
2550 switch (tObj->DepthMode) {
2551 case GL_LUMINANCE:
2552 texel[i][RCOMP] = result;
2553 texel[i][GCOMP] = result;
2554 texel[i][BCOMP] = result;
2555 texel[i][ACOMP] = CHAN_MAX;
2556 break;
2557 case GL_INTENSITY:
2558 texel[i][RCOMP] = result;
2559 texel[i][GCOMP] = result;
2560 texel[i][BCOMP] = result;
2561 texel[i][ACOMP] = result;
2562 break;
2563 case GL_ALPHA:
2564 texel[i][RCOMP] = 0;
2565 texel[i][GCOMP] = 0;
2566 texel[i][BCOMP] = 0;
2567 texel[i][ACOMP] = result;
2568 break;
2569 default:
2570 _mesa_problem(ctx, "Bad depth texture mode");
2571 }
2572 } /* for */
2573 } /* if filter */
2574 }
2575
2576
2577 #if 0
2578 /*
2579 * Experimental depth texture sampling function.
2580 */
2581 static void
2582 sample_depth_texture2(const GLcontext *ctx,
2583 const struct gl_texture_unit *texUnit,
2584 GLuint n, const GLfloat texcoords[][4],
2585 GLchan texel[][4])
2586 {
2587 const struct gl_texture_object *texObj = texUnit->_Current;
2588 const GLint baseLevel = texObj->BaseLevel;
2589 const struct gl_texture_image *texImage = texObj->Image[0][baseLevel];
2590 const GLuint width = texImage->Width;
2591 const GLuint height = texImage->Height;
2592 GLchan ambient;
2593 GLboolean lequal, gequal;
2594
2595 if (texObj->Target != GL_TEXTURE_2D) {
2596 _mesa_problem(ctx, "only 2-D depth textures supported at this time");
2597 return;
2598 }
2599
2600 if (texObj->MinFilter != texObj->MagFilter) {
2601 _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
2602 return;
2603 }
2604
2605 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2606 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2607 * isn't a depth texture.
2608 */
2609 if (texImage->Format != GL_DEPTH_COMPONENT) {
2610 _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2611 return;
2612 }
2613
2614 UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
2615
2616 if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2617 lequal = GL_TRUE;
2618 gequal = GL_FALSE;
2619 }
2620 else {
2621 lequal = GL_FALSE;
2622 gequal = GL_TRUE;
2623 }
2624
2625 {
2626 GLuint i;
2627 for (i = 0; i < n; i++) {
2628 const GLint K = 3;
2629 GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
2630 GLfloat w;
2631 GLchan lum;
2632 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0],
2633 width, col);
2634 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1],
2635 height, row);
2636
2637 imin = col - K;
2638 imax = col + K;
2639 jmin = row - K;
2640 jmax = row + K;
2641
2642 if (imin < 0) imin = 0;
2643 if (imax >= width) imax = width - 1;
2644 if (jmin < 0) jmin = 0;
2645 if (jmax >= height) jmax = height - 1;
2646
2647 samples = (imax - imin + 1) * (jmax - jmin + 1);
2648 count = 0;
2649 for (jj = jmin; jj <= jmax; jj++) {
2650 for (ii = imin; ii <= imax; ii++) {
2651 GLfloat depthSample;
2652 texImage->FetchTexelf(texImage, ii, jj, 0, &depthSample);
2653 if ((depthSample <= r[i] && lequal) ||
2654 (depthSample >= r[i] && gequal)) {
2655 count++;
2656 }
2657 }
2658 }
2659
2660 w = (GLfloat) count / (GLfloat) samples;
2661 w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
2662 lum = (GLint) w;
2663
2664 texel[i][RCOMP] = lum;
2665 texel[i][GCOMP] = lum;
2666 texel[i][BCOMP] = lum;
2667 texel[i][ACOMP] = CHAN_MAX;
2668 }
2669 }
2670 }
2671 #endif
2672
2673
2674 /**
2675 * We use this function when a texture object is in an "incomplete" state.
2676 * When a fragment program attempts to sample an incomplete texture we
2677 * return black (see issue 23 in GL_ARB_fragment_program spec).
2678 * Note: fragment programss don't observe the texture enable/disable flags.
2679 */
2680 static void
2681 null_sample_func( GLcontext *ctx, GLuint texUnit,
2682 const struct gl_texture_object *tObj, GLuint n,
2683 const GLfloat texcoords[][4], const GLfloat lambda[],
2684 GLchan rgba[][4])
2685 {
2686 GLuint i;
2687 (void) ctx;
2688 (void) texUnit;
2689 (void) tObj;
2690 (void) texcoords;
2691 (void) lambda;
2692 for (i = 0; i < n; i++) {
2693 rgba[i][RCOMP] = 0;
2694 rgba[i][GCOMP] = 0;
2695 rgba[i][BCOMP] = 0;
2696 rgba[i][ACOMP] = CHAN_MAX;
2697 }
2698 }
2699
2700
2701 /**
2702 * Setup the texture sampling function for this texture object.
2703 */
2704 texture_sample_func
2705 _swrast_choose_texture_sample_func( GLcontext *ctx,
2706 const struct gl_texture_object *t )
2707 {
2708 if (!t || !t->Complete) {
2709 return &null_sample_func;
2710 }
2711 else {
2712 const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
2713 const GLenum format = t->Image[0][t->BaseLevel]->Format;
2714
2715 switch (t->Target) {
2716 case GL_TEXTURE_1D:
2717 if (format == GL_DEPTH_COMPONENT) {
2718 return &sample_depth_texture;
2719 }
2720 else if (needLambda) {
2721 return &sample_lambda_1d;
2722 }
2723 else if (t->MinFilter == GL_LINEAR) {
2724 return &sample_linear_1d;
2725 }
2726 else {
2727 ASSERT(t->MinFilter == GL_NEAREST);
2728 return &sample_nearest_1d;
2729 }
2730 case GL_TEXTURE_2D:
2731 if (format == GL_DEPTH_COMPONENT) {
2732 return &sample_depth_texture;
2733 }
2734 else if (needLambda) {
2735 return &sample_lambda_2d;
2736 }
2737 else if (t->MinFilter == GL_LINEAR) {
2738 return &sample_linear_2d;
2739 }
2740 else {
2741 GLint baseLevel = t->BaseLevel;
2742 ASSERT(t->MinFilter == GL_NEAREST);
2743 if (t->WrapS == GL_REPEAT &&
2744 t->WrapT == GL_REPEAT &&
2745 t->_IsPowerOfTwo &&
2746 t->Image[0][baseLevel]->Border == 0 &&
2747 t->Image[0][baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
2748 return &opt_sample_rgb_2d;
2749 }
2750 else if (t->WrapS == GL_REPEAT &&
2751 t->WrapT == GL_REPEAT &&
2752 t->_IsPowerOfTwo &&
2753 t->Image[0][baseLevel]->Border == 0 &&
2754 t->Image[0][baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
2755 return &opt_sample_rgba_2d;
2756 }
2757 else {
2758 return &sample_nearest_2d;
2759 }
2760 }
2761 case GL_TEXTURE_3D:
2762 if (needLambda) {
2763 return &sample_lambda_3d;
2764 }
2765 else if (t->MinFilter == GL_LINEAR) {
2766 return &sample_linear_3d;
2767 }
2768 else {
2769 ASSERT(t->MinFilter == GL_NEAREST);
2770 return &sample_nearest_3d;
2771 }
2772 case GL_TEXTURE_CUBE_MAP:
2773 if (needLambda) {
2774 return &sample_lambda_cube;
2775 }
2776 else if (t->MinFilter == GL_LINEAR) {
2777 return &sample_linear_cube;
2778 }
2779 else {
2780 ASSERT(t->MinFilter == GL_NEAREST);
2781 return &sample_nearest_cube;
2782 }
2783 case GL_TEXTURE_RECTANGLE_NV:
2784 if (needLambda) {
2785 return &sample_lambda_rect;
2786 }
2787 else if (t->MinFilter == GL_LINEAR) {
2788 return &sample_linear_rect;
2789 }
2790 else {
2791 ASSERT(t->MinFilter == GL_NEAREST);
2792 return &sample_nearest_rect;
2793 }
2794 default:
2795 _mesa_problem(ctx,
2796 "invalid target in _swrast_choose_texture_sample_func");
2797 return &null_sample_func;
2798 }
2799 }
2800 }
2801
2802
2803 #define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
2804 #define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
2805
2806
2807 /**
2808 * Do texture application for GL_ARB/EXT_texture_env_combine.
2809 * This function also supports GL_{EXT,ARB}_texture_env_dot3 and
2810 * GL_ATI_texture_env_combine3. Since "classic" texture environments are
2811 * implemented using GL_ARB_texture_env_combine-like state, this same function
2812 * is used for classic texture environment application as well.
2813 *
2814 * \param ctx rendering context
2815 * \param textureUnit the texture unit to apply
2816 * \param n number of fragments to process (span width)
2817 * \param primary_rgba incoming fragment color array
2818 * \param texelBuffer pointer to texel colors for all texture units
2819 *
2820 * \param rgba incoming colors, which get modified here
2821 */
2822 static INLINE void
2823 texture_combine( const GLcontext *ctx, GLuint unit, GLuint n,
2824 CONST GLchan (*primary_rgba)[4],
2825 CONST GLchan *texelBuffer,
2826 GLchan (*rgba)[4] )
2827 {
2828 const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
2829 const GLchan (*argRGB [3])[4];
2830 const GLchan (*argA [3])[4];
2831 const GLuint RGBshift = textureUnit->_CurrentCombine->ScaleShiftRGB;
2832 const GLuint Ashift = textureUnit->_CurrentCombine->ScaleShiftA;
2833 #if CHAN_TYPE == GL_FLOAT
2834 const GLchan RGBmult = (GLfloat) (1 << RGBshift);
2835 const GLchan Amult = (GLfloat) (1 << Ashift);
2836 static const GLchan one[4] = { 1.0, 1.0, 1.0, 1.0 };
2837 static const GLchan zero[4] = { 0.0, 0.0, 0.0, 0.0 };
2838 #else
2839 const GLint half = (CHAN_MAX + 1) / 2;
2840 static const GLchan one[4] = { CHAN_MAX, CHAN_MAX, CHAN_MAX, CHAN_MAX };
2841 static const GLchan zero[4] = { 0, 0, 0, 0 };
2842 #endif
2843 GLuint i, j;
2844 GLuint numColorArgs;
2845 GLuint numAlphaArgs;
2846
2847 /* GLchan ccolor[3][4]; */
2848 DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4); /* mac 32k limitation */
2849 CHECKARRAY(ccolor, return); /* mac 32k limitation */
2850
2851 ASSERT(ctx->Extensions.EXT_texture_env_combine ||
2852 ctx->Extensions.ARB_texture_env_combine);
2853 ASSERT(SWRAST_CONTEXT(ctx)->_AnyTextureCombine);
2854
2855
2856 /*
2857 printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
2858 textureUnit->_CurrentCombine->ModeRGB,
2859 textureUnit->_CurrentCombine->ModeA,
2860 textureUnit->_CurrentCombine->SourceRGB[0],
2861 textureUnit->_CurrentCombine->SourceA[0],
2862 textureUnit->_CurrentCombine->SourceRGB[1],
2863 textureUnit->_CurrentCombine->SourceA[1]);
2864 */
2865
2866 /*
2867 * Do operand setup for up to 3 operands. Loop over the terms.
2868 */
2869 numColorArgs = textureUnit->_CurrentCombine->_NumArgsRGB;
2870 numAlphaArgs = textureUnit->_CurrentCombine->_NumArgsA;
2871
2872 for (j = 0; j < numColorArgs; j++) {
2873 const GLenum srcRGB = textureUnit->_CurrentCombine->SourceRGB[j];
2874
2875
2876 switch (srcRGB) {
2877 case GL_TEXTURE:
2878 argRGB[j] = (const GLchan (*)[4])
2879 (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
2880 break;
2881 case GL_PRIMARY_COLOR:
2882 argRGB[j] = primary_rgba;
2883 break;
2884 case GL_PREVIOUS:
2885 argRGB[j] = (const GLchan (*)[4]) rgba;
2886 break;
2887 case GL_CONSTANT:
2888 {
2889 GLchan (*c)[4] = ccolor[j];
2890 GLchan red, green, blue, alpha;
2891 UNCLAMPED_FLOAT_TO_CHAN(red, textureUnit->EnvColor[0]);
2892 UNCLAMPED_FLOAT_TO_CHAN(green, textureUnit->EnvColor[1]);
2893 UNCLAMPED_FLOAT_TO_CHAN(blue, textureUnit->EnvColor[2]);
2894 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
2895 for (i = 0; i < n; i++) {
2896 c[i][RCOMP] = red;
2897 c[i][GCOMP] = green;
2898 c[i][BCOMP] = blue;
2899 c[i][ACOMP] = alpha;
2900 }
2901 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
2902 }
2903 break;
2904 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
2905 */
2906 case GL_ZERO:
2907 argRGB[j] = & zero;
2908 break;
2909 case GL_ONE:
2910 argRGB[j] = & one;
2911 break;
2912 default:
2913 /* ARB_texture_env_crossbar source */
2914 {
2915 const GLuint srcUnit = srcRGB - GL_TEXTURE0;
2916 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
2917 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
2918 return;
2919 argRGB[j] = (const GLchan (*)[4])
2920 (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
2921 }
2922 }
2923
2924 if (textureUnit->_CurrentCombine->OperandRGB[j] != GL_SRC_COLOR) {
2925 const GLchan (*src)[4] = argRGB[j];
2926 GLchan (*dst)[4] = ccolor[j];
2927
2928 /* point to new arg[j] storage */
2929 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
2930
2931 if (textureUnit->_CurrentCombine->OperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
2932 for (i = 0; i < n; i++) {
2933 dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
2934 dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
2935 dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
2936 }
2937 }
2938 else if (textureUnit->_CurrentCombine->OperandRGB[j] == GL_SRC_ALPHA) {
2939 for (i = 0; i < n; i++) {
2940 dst[i][RCOMP] = src[i][ACOMP];
2941 dst[i][GCOMP] = src[i][ACOMP];
2942 dst[i][BCOMP] = src[i][ACOMP];
2943 }
2944 }
2945 else {
2946 ASSERT(textureUnit->_CurrentCombine->OperandRGB[j] ==GL_ONE_MINUS_SRC_ALPHA);
2947 for (i = 0; i < n; i++) {
2948 dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
2949 dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
2950 dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
2951 }
2952 }
2953 }
2954 }
2955
2956
2957 for (j = 0; j < numAlphaArgs; j++) {
2958 const GLenum srcA = textureUnit->_CurrentCombine->SourceA[j];
2959
2960 switch (srcA) {
2961 case GL_TEXTURE:
2962 argA[j] = (const GLchan (*)[4])
2963 (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
2964 break;
2965 case GL_PRIMARY_COLOR:
2966 argA[j] = primary_rgba;
2967 break;
2968 case GL_PREVIOUS:
2969 argA[j] = (const GLchan (*)[4]) rgba;
2970 break;
2971 case GL_CONSTANT:
2972 {
2973 GLchan alpha, (*c)[4] = ccolor[j];
2974 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
2975 for (i = 0; i < n; i++)
2976 c[i][ACOMP] = alpha;
2977 argA[j] = (const GLchan (*)[4]) ccolor[j];
2978 }
2979 break;
2980 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
2981 */
2982 case GL_ZERO:
2983 argA[j] = & zero;
2984 break;
2985 case GL_ONE:
2986 argA[j] = & one;
2987 break;
2988 default:
2989 /* ARB_texture_env_crossbar source */
2990 {
2991 const GLuint srcUnit = srcA - GL_TEXTURE0;
2992 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
2993 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
2994 return;
2995 argA[j] = (const GLchan (*)[4])
2996 (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
2997 }
2998 }
2999
3000 if (textureUnit->_CurrentCombine->OperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
3001 const GLchan (*src)[4] = argA[j];
3002 GLchan (*dst)[4] = ccolor[j];
3003 argA[j] = (const GLchan (*)[4]) ccolor[j];
3004 for (i = 0; i < n; i++) {
3005 dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
3006 }
3007 }
3008 }
3009
3010 /*
3011 * Do the texture combine.
3012 */
3013 switch (textureUnit->_CurrentCombine->ModeRGB) {
3014 case GL_REPLACE:
3015 {
3016 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3017 if (RGBshift) {
3018 for (i = 0; i < n; i++) {
3019 #if CHAN_TYPE == GL_FLOAT
3020 rgba[i][RCOMP] = arg0[i][RCOMP] * RGBmult;
3021 rgba[i][GCOMP] = arg0[i][GCOMP] * RGBmult;
3022 rgba[i][BCOMP] = arg0[i][BCOMP] * RGBmult;
3023 #else
3024 GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
3025 GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
3026 GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
3027 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3028 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3029 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3030 #endif
3031 }
3032 }
3033 else {
3034 for (i = 0; i < n; i++) {
3035 rgba[i][RCOMP] = arg0[i][RCOMP];
3036 rgba[i][GCOMP] = arg0[i][GCOMP];
3037 rgba[i][BCOMP] = arg0[i][BCOMP];
3038 }
3039 }
3040 }
3041 break;
3042 case GL_MODULATE:
3043 {
3044 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3045 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3046 #if CHAN_TYPE != GL_FLOAT
3047 const GLint shift = CHAN_BITS - RGBshift;
3048 #endif
3049 for (i = 0; i < n; i++) {
3050 #if CHAN_TYPE == GL_FLOAT
3051 rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * RGBmult;
3052 rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * RGBmult;
3053 rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * RGBmult;
3054 #else
3055 GLuint r = PROD(arg0[i][RCOMP], arg1[i][RCOMP]) >> shift;
3056 GLuint g = PROD(arg0[i][GCOMP], arg1[i][GCOMP]) >> shift;
3057 GLuint b = PROD(arg0[i][BCOMP], arg1[i][BCOMP]) >> shift;
3058 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3059 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3060 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3061 #endif
3062 }
3063 }
3064 break;
3065 case GL_ADD:
3066 {
3067 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3068 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3069 for (i = 0; i < n; i++) {
3070 #if CHAN_TYPE == GL_FLOAT
3071 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * RGBmult;
3072 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * RGBmult;
3073 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * RGBmult;
3074 #else
3075 GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
3076 GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
3077 GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
3078 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3079 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3080 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3081 #endif
3082 }
3083 }
3084 break;
3085 case GL_ADD_SIGNED:
3086 {
3087 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3088 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3089 for (i = 0; i < n; i++) {
3090 #if CHAN_TYPE == GL_FLOAT
3091 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5) * RGBmult;
3092 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5) * RGBmult;
3093 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5) * RGBmult;
3094 #else
3095 GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] -half;
3096 GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] -half;
3097 GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] -half;
3098 r = (r < 0) ? 0 : r << RGBshift;
3099 g = (g < 0) ? 0 : g << RGBshift;
3100 b = (b < 0) ? 0 : b << RGBshift;
3101 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3102 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3103 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3104 #endif
3105 }
3106 }
3107 break;
3108 case GL_INTERPOLATE:
3109 {
3110 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3111 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3112 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3113 #if CHAN_TYPE != GL_FLOAT
3114 const GLint shift = CHAN_BITS - RGBshift;
3115 #endif
3116 for (i = 0; i < n; i++) {
3117 #if CHAN_TYPE == GL_FLOAT
3118 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
3119 arg1[i][RCOMP] * (CHAN_MAXF - arg2[i][RCOMP])) * RGBmult;
3120 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
3121 arg1[i][GCOMP] * (CHAN_MAXF - arg2[i][GCOMP])) * RGBmult;
3122 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
3123 arg1[i][BCOMP] * (CHAN_MAXF - arg2[i][BCOMP])) * RGBmult;
3124 #else
3125 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3126 + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
3127 >> shift;
3128 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3129 + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
3130 >> shift;
3131 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3132 + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
3133 >> shift;
3134 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3135 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3136 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3137 #endif
3138 }
3139 }
3140 break;
3141 case GL_SUBTRACT:
3142 {
3143 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3144 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3145 for (i = 0; i < n; i++) {
3146 #if CHAN_TYPE == GL_FLOAT
3147 rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * RGBmult;
3148 rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * RGBmult;
3149 rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * RGBmult;
3150 #else
3151 GLint r = ((GLint) arg0[i][RCOMP] - (GLint) arg1[i][RCOMP]) << RGBshift;
3152 GLint g = ((GLint) arg0[i][GCOMP] - (GLint) arg1[i][GCOMP]) << RGBshift;
3153 GLint b = ((GLint) arg0[i][BCOMP] - (GLint) arg1[i][BCOMP]) << RGBshift;
3154 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3155 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3156 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3157 #endif
3158 }
3159 }
3160 break;
3161 case GL_DOT3_RGB_EXT:
3162 case GL_DOT3_RGBA_EXT:
3163 {
3164 /* Do not scale the result by 1 2 or 4 */
3165 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3166 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3167 for (i = 0; i < n; i++) {
3168 #if CHAN_TYPE == GL_FLOAT
3169 GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
3170 (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
3171 (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
3172 * 4.0F;
3173 dot = CLAMP(dot, 0.0F, CHAN_MAXF);
3174 #else
3175 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
3176 (GLint)arg1[i][RCOMP] - half) +
3177 S_PROD((GLint)arg0[i][GCOMP] - half,
3178 (GLint)arg1[i][GCOMP] - half) +
3179 S_PROD((GLint)arg0[i][BCOMP] - half,
3180 (GLint)arg1[i][BCOMP] - half)) >> 6;
3181 dot = CLAMP(dot, 0, CHAN_MAX);
3182 #endif
3183 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
3184 }
3185 }
3186 break;
3187 case GL_DOT3_RGB:
3188 case GL_DOT3_RGBA:
3189 {
3190 /* DO scale the result by 1 2 or 4 */
3191 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3192 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3193 for (i = 0; i < n; i++) {
3194 #if CHAN_TYPE == GL_FLOAT
3195 GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
3196 (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
3197 (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
3198 * 4.0F * RGBmult;
3199 dot = CLAMP(dot, 0.0, CHAN_MAXF);
3200 #else
3201 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
3202 (GLint)arg1[i][RCOMP] - half) +
3203 S_PROD((GLint)arg0[i][GCOMP] - half,
3204 (GLint)arg1[i][GCOMP] - half) +
3205 S_PROD((GLint)arg0[i][BCOMP] - half,
3206 (GLint)arg1[i][BCOMP] - half)) >> 6;
3207 dot <<= RGBshift;
3208 dot = CLAMP(dot, 0, CHAN_MAX);
3209 #endif
3210 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
3211 }
3212 }
3213 break;
3214 case GL_MODULATE_ADD_ATI:
3215 {
3216 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3217 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3218 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3219 #if CHAN_TYPE != GL_FLOAT
3220 const GLint shift = CHAN_BITS - RGBshift;
3221 #endif
3222 for (i = 0; i < n; i++) {
3223 #if CHAN_TYPE == GL_FLOAT
3224 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP]) * RGBmult;
3225 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP]) * RGBmult;
3226 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP]) * RGBmult;
3227 #else
3228 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3229 + ((GLuint) arg1[i][RCOMP] << CHAN_BITS)) >> shift;
3230 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3231 + ((GLuint) arg1[i][GCOMP] << CHAN_BITS)) >> shift;
3232 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3233 + ((GLuint) arg1[i][BCOMP] << CHAN_BITS)) >> shift;
3234 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3235 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3236 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3237 #endif
3238 }
3239 }
3240 break;
3241 case GL_MODULATE_SIGNED_ADD_ATI:
3242 {
3243 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3244 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3245 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3246 #if CHAN_TYPE != GL_FLOAT
3247 const GLint shift = CHAN_BITS - RGBshift;
3248 #endif
3249 for (i = 0; i < n; i++) {
3250 #if CHAN_TYPE == GL_FLOAT
3251 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP] - 0.5) * RGBmult;
3252 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP] - 0.5) * RGBmult;
3253 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP] - 0.5) * RGBmult;
3254 #else
3255 GLint r = (S_PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3256 + (((GLint) arg1[i][RCOMP] - half) << CHAN_BITS))
3257 >> shift;
3258 GLint g = (S_PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3259 + (((GLint) arg1[i][GCOMP] - half) << CHAN_BITS))
3260 >> shift;
3261 GLint b = (S_PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3262 + (((GLint) arg1[i][BCOMP] - half) << CHAN_BITS))
3263 >> shift;
3264 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3265 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3266 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3267 #endif
3268 }
3269 }
3270 break;
3271 case GL_MODULATE_SUBTRACT_ATI:
3272 {
3273 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3274 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3275 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3276 #if CHAN_TYPE != GL_FLOAT
3277 const GLint shift = CHAN_BITS - RGBshift;
3278 #endif
3279 for (i = 0; i < n; i++) {
3280 #if CHAN_TYPE == GL_FLOAT
3281 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) - arg1[i][RCOMP]) * RGBmult;
3282 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) - arg1[i][GCOMP]) * RGBmult;
3283 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) - arg1[i][BCOMP]) * RGBmult;
3284 #else
3285 GLint r = (S_PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3286 - ((GLint) arg1[i][RCOMP] << CHAN_BITS))
3287 >> shift;
3288 GLint g = (S_PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3289 - ((GLint) arg1[i][GCOMP] << CHAN_BITS))
3290 >> shift;
3291 GLint b = (S_PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3292 - ((GLint) arg1[i][BCOMP] << CHAN_BITS))
3293 >> shift;
3294 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3295 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3296 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3297 #endif
3298 }
3299 }
3300 break;
3301 default:
3302 _mesa_problem(ctx, "invalid combine mode");
3303 }
3304
3305 switch (textureUnit->_CurrentCombine->ModeA) {
3306 case GL_REPLACE:
3307 {
3308 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3309 if (Ashift) {
3310 for (i = 0; i < n; i++) {
3311 #if CHAN_TYPE == GL_FLOAT
3312 GLchan a = arg0[i][ACOMP] * Amult;
3313 #else
3314 GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
3315 #endif
3316 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3317 }
3318 }
3319 else {
3320 for (i = 0; i < n; i++) {
3321 rgba[i][ACOMP] = arg0[i][ACOMP];
3322 }
3323 }
3324 }
3325 break;
3326 case GL_MODULATE:
3327 {
3328 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3329 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3330 #if CHAN_TYPE != GL_FLOAT
3331 const GLint shift = CHAN_BITS - Ashift;
3332 #endif
3333 for (i = 0; i < n; i++) {
3334 #if CHAN_TYPE == GL_FLOAT
3335 rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * Amult;
3336 #else
3337 GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
3338 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3339 #endif
3340 }
3341 }
3342 break;
3343 case GL_ADD:
3344 {
3345 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3346 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3347 for (i = 0; i < n; i++) {
3348 #if CHAN_TYPE == GL_FLOAT
3349 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * Amult;
3350 #else
3351 GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
3352 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3353 #endif
3354 }
3355 }
3356 break;
3357 case GL_ADD_SIGNED:
3358 {
3359 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3360 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3361 for (i = 0; i < n; i++) {
3362 #if CHAN_TYPE == GL_FLOAT
3363 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * Amult;
3364 #else
3365 GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] -half;
3366 a = (a < 0) ? 0 : a << Ashift;
3367 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3368 #endif
3369 }
3370 }
3371 break;
3372 case GL_INTERPOLATE:
3373 {
3374 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3375 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3376 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3377 #if CHAN_TYPE != GL_FLOAT
3378 const GLint shift = CHAN_BITS - Ashift;
3379 #endif
3380 for (i=0; i<n; i++) {
3381 #if CHAN_TYPE == GL_FLOAT
3382 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
3383 arg1[i][ACOMP] * (CHAN_MAXF - arg2[i][ACOMP]))
3384 * Amult;
3385 #else
3386 GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3387 + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
3388 >> shift;
3389 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3390 #endif
3391 }
3392 }
3393 break;
3394 case GL_SUBTRACT:
3395 {
3396 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3397 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3398 for (i = 0; i < n; i++) {
3399 #if CHAN_TYPE == GL_FLOAT
3400 rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * Amult;
3401 #else
3402 GLint a = ((GLint) arg0[i][ACOMP] - (GLint) arg1[i][ACOMP]) << Ashift;
3403 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3404 #endif
3405 }
3406 }
3407 break;
3408 case GL_MODULATE_ADD_ATI:
3409 {
3410 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3411 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3412 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3413 #if CHAN_TYPE != GL_FLOAT
3414 const GLint shift = CHAN_BITS - Ashift;
3415 #endif
3416 for (i = 0; i < n; i++) {
3417 #if CHAN_TYPE == GL_FLOAT
3418 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP]) * Amult;
3419 #else
3420 GLint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3421 + ((GLuint) arg1[i][ACOMP] << CHAN_BITS))
3422 >> shift;
3423 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3424 #endif
3425 }
3426 }
3427 break;
3428 case GL_MODULATE_SIGNED_ADD_ATI:
3429 {
3430 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3431 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3432 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3433 #if CHAN_TYPE != GL_FLOAT
3434 const GLint shift = CHAN_BITS - Ashift;
3435 #endif
3436 for (i = 0; i < n; i++) {
3437 #if CHAN_TYPE == GL_FLOAT
3438 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP] - 0.5F) * Amult;
3439 #else
3440 GLint a = (S_PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3441 + (((GLint) arg1[i][ACOMP] - half) << CHAN_BITS))
3442 >> shift;
3443 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3444 #endif
3445 }
3446 }
3447 break;
3448 case GL_MODULATE_SUBTRACT_ATI:
3449 {
3450 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3451 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3452 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3453 #if CHAN_TYPE != GL_FLOAT
3454 const GLint shift = CHAN_BITS - Ashift;
3455 #endif
3456 for (i = 0; i < n; i++) {
3457 #if CHAN_TYPE == GL_FLOAT
3458 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) - arg1[i][ACOMP]) * Amult;
3459 #else
3460 GLint a = (S_PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3461 - ((GLint) arg1[i][ACOMP] << CHAN_BITS))
3462 >> shift;
3463 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3464 #endif
3465 }
3466 }
3467 break;
3468 default:
3469 _mesa_problem(ctx, "invalid combine mode");
3470 }
3471
3472 /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
3473 * This is kind of a kludge. It would have been better if the spec
3474 * were written such that the GL_COMBINE_ALPHA value could be set to
3475 * GL_DOT3.
3476 */
3477 if (textureUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA_EXT ||
3478 textureUnit->_CurrentCombine->ModeRGB == GL_DOT3_RGBA) {
3479 for (i = 0; i < n; i++) {
3480 rgba[i][ACOMP] = rgba[i][RCOMP];
3481 }
3482 }
3483 UNDEFARRAY(ccolor); /* mac 32k limitation */
3484 }
3485 #undef PROD
3486
3487
3488 /**
3489 * Apply a conventional OpenGL texture env mode (REPLACE, ADD, BLEND,
3490 * MODULATE, or DECAL) to an array of fragments.
3491 * Input: textureUnit - pointer to texture unit to apply
3492 * format - base internal texture format
3493 * n - number of fragments
3494 * primary_rgba - primary colors (may alias rgba for single texture)
3495 * texels - array of texel colors
3496 * InOut: rgba - incoming fragment colors modified by texel colors
3497 * according to the texture environment mode.
3498 */
3499 static void
3500 texture_apply( const GLcontext *ctx,
3501 const struct gl_texture_unit *texUnit,
3502 GLuint n,
3503 CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
3504 GLchan rgba[][4] )
3505 {
3506 GLint baseLevel;
3507 GLuint i;
3508 GLint Rc, Gc, Bc, Ac;
3509 GLenum format;
3510 (void) primary_rgba;
3511
3512 ASSERT(texUnit);
3513 ASSERT(texUnit->_Current);
3514
3515 baseLevel = texUnit->_Current->BaseLevel;
3516 ASSERT(texUnit->_Current->Image[0][baseLevel]);
3517
3518 format = texUnit->_Current->Image[0][baseLevel]->Format;
3519
3520 if (format == GL_COLOR_INDEX || format == GL_YCBCR_MESA) {
3521 format = GL_RGBA; /* a bit of a hack */
3522 }
3523 else if (format == GL_DEPTH_COMPONENT) {
3524 format = texUnit->_Current->DepthMode;
3525 }
3526
3527 switch (texUnit->EnvMode) {
3528 case GL_REPLACE:
3529 switch (format) {
3530 case GL_ALPHA:
3531 for (i=0;i<n;i++) {
3532 /* Cv = Cf */
3533 /* Av = At */
3534 rgba[i][ACOMP] = texel[i][ACOMP];
3535 }
3536 break;
3537 case GL_LUMINANCE:
3538 for (i=0;i<n;i++) {
3539 /* Cv = Lt */
3540 GLchan Lt = texel[i][RCOMP];
3541 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
3542 /* Av = Af */
3543 }
3544 break;
3545 case GL_LUMINANCE_ALPHA:
3546 for (i=0;i<n;i++) {
3547 GLchan Lt = texel[i][RCOMP];
3548 /* Cv = Lt */
3549 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
3550 /* Av = At */
3551 rgba[i][ACOMP] = texel[i][ACOMP];
3552 }
3553 break;
3554 case GL_INTENSITY:
3555 for (i=0;i<n;i++) {
3556 /* Cv = It */
3557 GLchan It = texel[i][RCOMP];
3558 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
3559 /* Av = It */
3560 rgba[i][ACOMP] = It;
3561 }
3562 break;
3563 case GL_RGB:
3564 for (i=0;i<n;i++) {
3565 /* Cv = Ct */
3566 rgba[i][RCOMP] = texel[i][RCOMP];
3567 rgba[i][GCOMP] = texel[i][GCOMP];
3568 rgba[i][BCOMP] = texel[i][BCOMP];
3569 /* Av = Af */
3570 }
3571 break;
3572 case GL_RGBA:
3573 for (i=0;i<n;i++) {
3574 /* Cv = Ct */
3575 rgba[i][RCOMP] = texel[i][RCOMP];
3576 rgba[i][GCOMP] = texel[i][GCOMP];
3577 rgba[i][BCOMP] = texel[i][BCOMP];
3578 /* Av = At */
3579 rgba[i][ACOMP] = texel[i][ACOMP];
3580 }
3581 break;
3582 default:
3583 _mesa_problem(ctx, "Bad format (GL_REPLACE) in texture_apply");
3584 return;
3585 }
3586 break;
3587
3588 case GL_MODULATE:
3589 switch (format) {
3590 case GL_ALPHA:
3591 for (i=0;i<n;i++) {
3592 /* Cv = Cf */
3593 /* Av = AfAt */
3594 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3595 }
3596 break;
3597 case GL_LUMINANCE:
3598 for (i=0;i<n;i++) {
3599 /* Cv = LtCf */
3600 GLchan Lt = texel[i][RCOMP];
3601 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
3602 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
3603 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
3604 /* Av = Af */
3605 }
3606 break;
3607 case GL_LUMINANCE_ALPHA:
3608 for (i=0;i<n;i++) {
3609 /* Cv = CfLt */
3610 GLchan Lt = texel[i][RCOMP];
3611 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
3612 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
3613 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
3614 /* Av = AfAt */
3615 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3616 }
3617 break;
3618 case GL_INTENSITY:
3619 for (i=0;i<n;i++) {
3620 /* Cv = CfIt */
3621 GLchan It = texel[i][RCOMP];
3622 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
3623 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
3624 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
3625 /* Av = AfIt */
3626 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
3627 }
3628 break;
3629 case GL_RGB:
3630 for (i=0;i<n;i++) {
3631 /* Cv = CfCt */
3632 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
3633 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
3634 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
3635 /* Av = Af */
3636 }
3637 break;
3638 case GL_RGBA:
3639 for (i=0;i<n;i++) {
3640 /* Cv = CfCt */
3641 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
3642 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
3643 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
3644 /* Av = AfAt */
3645 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3646 }
3647 break;
3648 default:
3649 _mesa_problem(ctx, "Bad format (GL_MODULATE) in texture_apply");
3650 return;
3651 }
3652 break;
3653
3654 case GL_DECAL:
3655 switch (format) {
3656 case GL_ALPHA:
3657 case GL_LUMINANCE:
3658 case GL_LUMINANCE_ALPHA:
3659 case GL_INTENSITY:
3660 /* undefined */
3661 break;
3662 case GL_RGB:
3663 for (i=0;i<n;i++) {
3664 /* Cv = Ct */
3665 rgba[i][RCOMP] = texel[i][RCOMP];
3666 rgba[i][GCOMP] = texel[i][GCOMP];
3667 rgba[i][BCOMP] = texel[i][BCOMP];
3668 /* Av = Af */
3669 }
3670 break;
3671 case GL_RGBA:
3672 for (i=0;i<n;i++) {
3673 /* Cv = Cf(1-At) + CtAt */
3674 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
3675 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
3676 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
3677 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
3678 /* Av = Af */
3679 }
3680 break;
3681 default:
3682 _mesa_problem(ctx, "Bad format (GL_DECAL) in texture_apply");
3683 return;
3684 }
3685 break;
3686
3687 case GL_BLEND:
3688 Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
3689 Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
3690 Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
3691 Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
3692 switch (format) {
3693 case GL_ALPHA:
3694 for (i=0;i<n;i++) {
3695 /* Cv = Cf */
3696 /* Av = AfAt */
3697 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
3698 }
3699 break;
3700 case GL_LUMINANCE:
3701 for (i=0;i<n;i++) {
3702 /* Cv = Cf(1-Lt) + CcLt */
3703 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
3704 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
3705 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
3706 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
3707 /* Av = Af */
3708 }
3709 break;
3710 case GL_LUMINANCE_ALPHA:
3711 for (i=0;i<n;i++) {
3712 /* Cv = Cf(1-Lt) + CcLt */
3713 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
3714 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
3715 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
3716 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
3717 /* Av = AfAt */
3718 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
3719 }
3720 break;
3721 case GL_INTENSITY:
3722 for (i=0;i<n;i++) {
3723 /* Cv = Cf(1-It) + CcIt */
3724 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
3725 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
3726 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
3727 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
3728 /* Av = Af(1-It) + Ac*It */
3729 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
3730 }
3731 break;
3732 case GL_RGB:
3733 for (i=0;i<n;i++) {
3734 /* Cv = Cf(1-Ct) + CcCt */
3735 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
3736 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
3737 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
3738 /* Av = Af */
3739 }
3740 break;
3741 case GL_RGBA:
3742 for (i=0;i<n;i++) {
3743 /* Cv = Cf(1-Ct) + CcCt */
3744 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
3745 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
3746 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
3747 /* Av = AfAt */
3748 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
3749 }
3750 break;
3751 default:
3752 _mesa_problem(ctx, "Bad format (GL_BLEND) in texture_apply");
3753 return;
3754 }
3755 break;
3756
3757 /* XXX don't clamp results if GLchan is float??? */
3758
3759 case GL_ADD: /* GL_EXT_texture_add_env */
3760 switch (format) {
3761 case GL_ALPHA:
3762 for (i=0;i<n;i++) {
3763 /* Rv = Rf */
3764 /* Gv = Gf */
3765 /* Bv = Bf */
3766 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
3767 }
3768 break;
3769 case GL_LUMINANCE:
3770 for (i=0;i<n;i++) {
3771 GLuint Lt = texel[i][RCOMP];
3772 GLuint r = rgba[i][RCOMP] + Lt;
3773 GLuint g = rgba[i][GCOMP] + Lt;
3774 GLuint b = rgba[i][BCOMP] + Lt;
3775 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3776 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3777 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3778 /* Av = Af */
3779 }
3780 break;
3781 case GL_LUMINANCE_ALPHA:
3782 for (i=0;i<n;i++) {
3783 GLuint Lt = texel[i][RCOMP];
3784 GLuint r = rgba[i][RCOMP] + Lt;
3785 GLuint g = rgba[i][GCOMP] + Lt;
3786 GLuint b = rgba[i][BCOMP] + Lt;
3787 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3788 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3789 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3790 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
3791 }
3792 break;
3793 case GL_INTENSITY:
3794 for (i=0;i<n;i++) {
3795 GLchan It = texel[i][RCOMP];
3796 GLuint r = rgba[i][RCOMP] + It;
3797 GLuint g = rgba[i][GCOMP] + It;
3798 GLuint b = rgba[i][BCOMP] + It;
3799 GLuint a = rgba[i][ACOMP] + It;
3800 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3801 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3802 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3803 rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
3804 }
3805 break;
3806 case GL_RGB:
3807 for (i=0;i<n;i++) {
3808 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
3809 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
3810 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
3811 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3812 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3813 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3814 /* Av = Af */
3815 }
3816 break;
3817 case GL_RGBA:
3818 for (i=0;i<n;i++) {
3819 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
3820 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
3821 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
3822 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3823 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3824 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3825 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
3826 }
3827 break;
3828 default:
3829 _mesa_problem(ctx, "Bad format (GL_ADD) in texture_apply");
3830 return;
3831 }
3832 break;
3833
3834 default:
3835 _mesa_problem(ctx, "Bad env mode in texture_apply");
3836 return;
3837 }
3838 }
3839
3840
3841
3842 /**
3843 * Apply texture mapping to a span of fragments.
3844 */
3845 void
3846 _swrast_texture_span( GLcontext *ctx, struct sw_span *span )
3847 {
3848 SWcontext *swrast = SWRAST_CONTEXT(ctx);
3849 GLchan primary_rgba[MAX_WIDTH][4];
3850 GLuint unit;
3851
3852 ASSERT(span->end < MAX_WIDTH);
3853 ASSERT(span->arrayMask & SPAN_TEXTURE);
3854
3855 /*
3856 * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
3857 */
3858 if (swrast->_AnyTextureCombine)
3859 MEMCPY(primary_rgba, span->array->rgba, 4 * span->end * sizeof(GLchan));
3860
3861 /*
3862 * Must do all texture sampling before combining in order to
3863 * accomodate GL_ARB_texture_env_crossbar.
3864 */
3865 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
3866 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
3867 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
3868 const struct gl_texture_object *curObj = texUnit->_Current;
3869 GLfloat *lambda = span->array->lambda[unit];
3870 GLchan (*texels)[4] = (GLchan (*)[4])
3871 (swrast->TexelBuffer + unit * (span->end * 4 * sizeof(GLchan)));
3872
3873 /* adjust texture lod (lambda) */
3874 if (span->arrayMask & SPAN_LAMBDA) {
3875 if (texUnit->LodBias + curObj->LodBias != 0.0F) {
3876 /* apply LOD bias, but don't clamp yet */
3877 const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias,
3878 -ctx->Const.MaxTextureLodBias,
3879 ctx->Const.MaxTextureLodBias);
3880 GLuint i;
3881 for (i = 0; i < span->end; i++) {
3882 lambda[i] += bias;
3883 }
3884 }
3885
3886 if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) {
3887 /* apply LOD clamping to lambda */
3888 const GLfloat min = curObj->MinLod;
3889 const GLfloat max = curObj->MaxLod;
3890 GLuint i;
3891 for (i = 0; i < span->end; i++) {
3892 GLfloat l = lambda[i];
3893 lambda[i] = CLAMP(l, min, max);
3894 }
3895 }
3896 }
3897
3898 /* Sample the texture (span->end fragments) */
3899 swrast->TextureSample[unit]( ctx, unit, texUnit->_Current, span->end,
3900 (const GLfloat (*)[4]) span->array->texcoords[unit],
3901 lambda, texels );
3902
3903 /* GL_SGI_texture_color_table */
3904 if (texUnit->ColorTableEnabled) {
3905 _mesa_lookup_rgba_chan(&texUnit->ColorTable, span->end, texels);
3906 }
3907 }
3908 }
3909
3910 /*
3911 * OK, now apply the texture (aka texture combine/blend).
3912 * We modify the span->color.rgba values.
3913 */
3914 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
3915 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
3916 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
3917 if (texUnit->_CurrentCombine != &texUnit->_EnvMode ) {
3918 texture_combine( ctx, unit, span->end,
3919 (CONST GLchan (*)[4]) primary_rgba,
3920 swrast->TexelBuffer,
3921 span->array->rgba );
3922 }
3923 else {
3924 /* conventional texture blend */
3925 const GLchan (*texels)[4] = (const GLchan (*)[4])
3926 (swrast->TexelBuffer + unit *
3927 (span->end * 4 * sizeof(GLchan)));
3928 texture_apply( ctx, texUnit, span->end,
3929 (CONST GLchan (*)[4]) primary_rgba, texels,
3930 span->array->rgba );
3931 }
3932 }
3933 }
3934 }