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