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