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