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