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