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