Initial support for floating point and signed texture formats.
[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[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[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[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[level ], texcoord[i], t0);
940 sample_1d_nearest(ctx, tObj, tObj->Image[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[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[level ], texcoord[i], t0);
970 sample_1d_linear(ctx, tObj, tObj->Image[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[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[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[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[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[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[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[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[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[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[level ], texcoord[i], t0);
1383 sample_2d_nearest(ctx, tObj, tObj->Image[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[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[level ], texcoord[i], t0);
1414 sample_2d_linear(ctx, tObj, tObj->Image[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[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[level ], texcoord[i], t0);
1446 sample_2d_linear_repeat(ctx, tObj, tObj->Image[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[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[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[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[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[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->Format) {
1596 case GL_RGB:
1597 opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1598 NULL, rgba + minStart);
1599 break;
1600 case GL_RGBA:
1601 opt_sample_rgba_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1602 NULL, rgba + minStart);
1603 break;
1604 default:
1605 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1606 NULL, rgba + minStart );
1607 }
1608 }
1609 else {
1610 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1611 NULL, rgba + minStart);
1612 }
1613 break;
1614 case GL_LINEAR:
1615 sample_linear_2d(ctx, texUnit, tObj, m, texcoords + minStart,
1616 NULL, rgba + minStart);
1617 break;
1618 case GL_NEAREST_MIPMAP_NEAREST:
1619 sample_2d_nearest_mipmap_nearest(ctx, tObj, m,
1620 texcoords + minStart,
1621 lambda + minStart, rgba + minStart);
1622 break;
1623 case GL_LINEAR_MIPMAP_NEAREST:
1624 sample_2d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
1625 lambda + minStart, rgba + minStart);
1626 break;
1627 case GL_NEAREST_MIPMAP_LINEAR:
1628 sample_2d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1629 lambda + minStart, rgba + minStart);
1630 break;
1631 case GL_LINEAR_MIPMAP_LINEAR:
1632 if (repeatNoBorderPOT)
1633 sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m,
1634 texcoords + minStart, lambda + minStart, rgba + minStart);
1635 else
1636 sample_2d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
1637 lambda + minStart, rgba + minStart);
1638 break;
1639 default:
1640 _mesa_problem(ctx, "Bad min filter in sample_2d_texture");
1641 return;
1642 }
1643 }
1644
1645 if (magStart < magEnd) {
1646 /* do the magnified texels */
1647 const GLuint m = magEnd - magStart;
1648
1649 switch (tObj->MagFilter) {
1650 case GL_NEAREST:
1651 if (repeatNoBorderPOT) {
1652 switch (tImg->Format) {
1653 case GL_RGB:
1654 opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1655 NULL, rgba + magStart);
1656 break;
1657 case GL_RGBA:
1658 opt_sample_rgba_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1659 NULL, rgba + magStart);
1660 break;
1661 default:
1662 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1663 NULL, rgba + magStart );
1664 }
1665 }
1666 else {
1667 sample_nearest_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1668 NULL, rgba + magStart);
1669 }
1670 break;
1671 case GL_LINEAR:
1672 sample_linear_2d(ctx, texUnit, tObj, m, texcoords + magStart,
1673 NULL, rgba + magStart);
1674 break;
1675 default:
1676 _mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
1677 }
1678 }
1679 }
1680
1681
1682
1683 /**********************************************************************/
1684 /* 3-D Texture Sampling Functions */
1685 /**********************************************************************/
1686
1687 /*
1688 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1689 */
1690 static void
1691 sample_3d_nearest(GLcontext *ctx,
1692 const struct gl_texture_object *tObj,
1693 const struct gl_texture_image *img,
1694 const GLfloat texcoord[4],
1695 GLchan rgba[4])
1696 {
1697 const GLint width = img->Width2; /* without border, power of two */
1698 const GLint height = img->Height2; /* without border, power of two */
1699 const GLint depth = img->Depth2; /* without border, power of two */
1700 GLint i, j, k;
1701
1702 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
1703 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoord[1], height, j);
1704 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, texcoord[2], depth, k);
1705
1706 if (i < 0 || i >= (GLint) img->Width ||
1707 j < 0 || j >= (GLint) img->Height ||
1708 k < 0 || k >= (GLint) img->Depth) {
1709 /* Need this test for GL_CLAMP_TO_BORDER mode */
1710 COPY_CHAN4(rgba, tObj->_BorderChan);
1711 }
1712 else {
1713 img->FetchTexelc(img, i, j, k, rgba);
1714 if (img->Format == GL_COLOR_INDEX) {
1715 palette_sample(ctx, tObj, rgba[0], rgba);
1716 }
1717 }
1718 }
1719
1720
1721
1722 /*
1723 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1724 */
1725 static void
1726 sample_3d_linear(GLcontext *ctx,
1727 const struct gl_texture_object *tObj,
1728 const struct gl_texture_image *img,
1729 const GLfloat texcoord[4],
1730 GLchan rgba[4])
1731 {
1732 const GLint width = img->Width2;
1733 const GLint height = img->Height2;
1734 const GLint depth = img->Depth2;
1735 GLint i0, j0, k0, i1, j1, k1;
1736 GLuint useBorderColor;
1737 GLfloat u, v, w;
1738
1739 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
1740 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoord[1], v, height, j0, j1);
1741 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, texcoord[2], w, depth, k0, k1);
1742
1743 useBorderColor = 0;
1744 if (img->Border) {
1745 i0 += img->Border;
1746 i1 += img->Border;
1747 j0 += img->Border;
1748 j1 += img->Border;
1749 k0 += img->Border;
1750 k1 += img->Border;
1751 }
1752 else {
1753 /* check if sampling texture border color */
1754 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
1755 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
1756 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
1757 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
1758 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
1759 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
1760 }
1761
1762 {
1763 const GLfloat a = FRAC(u);
1764 const GLfloat b = FRAC(v);
1765 const GLfloat c = FRAC(w);
1766
1767 #if CHAN_TYPE == GL_FLOAT || CHAN_TYPE == GL_UNSIGNED_SHORT
1768 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1769 GLfloat w000 = (1.0F-a) * (1.0F-b) * (1.0F-c);
1770 GLfloat w100 = a * (1.0F-b) * (1.0F-c);
1771 GLfloat w010 = (1.0F-a) * b * (1.0F-c);
1772 GLfloat w110 = a * b * (1.0F-c);
1773 GLfloat w001 = (1.0F-a) * (1.0F-b) * c ;
1774 GLfloat w101 = a * (1.0F-b) * c ;
1775 GLfloat w011 = (1.0F-a) * b * c ;
1776 GLfloat w111 = a * b * c ;
1777 #else /* CHAN_BITS == 8 */
1778 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
1779 GLint w000 = IROUND_POS((1.0F-a) * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1780 GLint w100 = IROUND_POS( a * (1.0F-b) * (1.0F-c) * WEIGHT_SCALE);
1781 GLint w010 = IROUND_POS((1.0F-a) * b * (1.0F-c) * WEIGHT_SCALE);
1782 GLint w110 = IROUND_POS( a * b * (1.0F-c) * WEIGHT_SCALE);
1783 GLint w001 = IROUND_POS((1.0F-a) * (1.0F-b) * c * WEIGHT_SCALE);
1784 GLint w101 = IROUND_POS( a * (1.0F-b) * c * WEIGHT_SCALE);
1785 GLint w011 = IROUND_POS((1.0F-a) * b * c * WEIGHT_SCALE);
1786 GLint w111 = IROUND_POS( a * b * c * WEIGHT_SCALE);
1787 #endif
1788
1789 GLchan t000[4], t010[4], t001[4], t011[4];
1790 GLchan t100[4], t110[4], t101[4], t111[4];
1791
1792 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
1793 COPY_CHAN4(t000, tObj->_BorderChan);
1794 }
1795 else {
1796 img->FetchTexelc(img, i0, j0, k0, t000);
1797 if (img->Format == GL_COLOR_INDEX) {
1798 palette_sample(ctx, tObj, t000[0], t000);
1799 }
1800 }
1801 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
1802 COPY_CHAN4(t100, tObj->_BorderChan);
1803 }
1804 else {
1805 img->FetchTexelc(img, i1, j0, k0, t100);
1806 if (img->Format == GL_COLOR_INDEX) {
1807 palette_sample(ctx, tObj, t100[0], t100);
1808 }
1809 }
1810 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
1811 COPY_CHAN4(t010, tObj->_BorderChan);
1812 }
1813 else {
1814 img->FetchTexelc(img, i0, j1, k0, t010);
1815 if (img->Format == GL_COLOR_INDEX) {
1816 palette_sample(ctx, tObj, t010[0], t010);
1817 }
1818 }
1819 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
1820 COPY_CHAN4(t110, tObj->_BorderChan);
1821 }
1822 else {
1823 img->FetchTexelc(img, i1, j1, k0, t110);
1824 if (img->Format == GL_COLOR_INDEX) {
1825 palette_sample(ctx, tObj, t110[0], t110);
1826 }
1827 }
1828
1829 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
1830 COPY_CHAN4(t001, tObj->_BorderChan);
1831 }
1832 else {
1833 img->FetchTexelc(img, i0, j0, k1, t001);
1834 if (img->Format == GL_COLOR_INDEX) {
1835 palette_sample(ctx, tObj, t001[0], t001);
1836 }
1837 }
1838 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
1839 COPY_CHAN4(t101, tObj->_BorderChan);
1840 }
1841 else {
1842 img->FetchTexelc(img, i1, j0, k1, t101);
1843 if (img->Format == GL_COLOR_INDEX) {
1844 palette_sample(ctx, tObj, t101[0], t101);
1845 }
1846 }
1847 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
1848 COPY_CHAN4(t011, tObj->_BorderChan);
1849 }
1850 else {
1851 img->FetchTexelc(img, i0, j1, k1, t011);
1852 if (img->Format == GL_COLOR_INDEX) {
1853 palette_sample(ctx, tObj, t011[0], t011);
1854 }
1855 }
1856 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
1857 COPY_CHAN4(t111, tObj->_BorderChan);
1858 }
1859 else {
1860 img->FetchTexelc(img, i1, j1, k1, t111);
1861 if (img->Format == GL_COLOR_INDEX) {
1862 palette_sample(ctx, tObj, t111[0], t111);
1863 }
1864 }
1865
1866 #if CHAN_TYPE == GL_FLOAT
1867 rgba[0] = w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1868 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0];
1869 rgba[1] = w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1870 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1];
1871 rgba[2] = w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1872 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2];
1873 rgba[3] = w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1874 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3];
1875 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
1876 rgba[0] = (GLchan) (w000*t000[0] + w010*t010[0] +
1877 w001*t001[0] + w011*t011[0] +
1878 w100*t100[0] + w110*t110[0] +
1879 w101*t101[0] + w111*t111[0] + 0.5);
1880 rgba[1] = (GLchan) (w000*t000[1] + w010*t010[1] +
1881 w001*t001[1] + w011*t011[1] +
1882 w100*t100[1] + w110*t110[1] +
1883 w101*t101[1] + w111*t111[1] + 0.5);
1884 rgba[2] = (GLchan) (w000*t000[2] + w010*t010[2] +
1885 w001*t001[2] + w011*t011[2] +
1886 w100*t100[2] + w110*t110[2] +
1887 w101*t101[2] + w111*t111[2] + 0.5);
1888 rgba[3] = (GLchan) (w000*t000[3] + w010*t010[3] +
1889 w001*t001[3] + w011*t011[3] +
1890 w100*t100[3] + w110*t110[3] +
1891 w101*t101[3] + w111*t111[3] + 0.5);
1892 #else /* CHAN_BITS == 8 */
1893 rgba[0] = (GLchan) (
1894 (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1895 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] )
1896 >> WEIGHT_SHIFT);
1897 rgba[1] = (GLchan) (
1898 (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1899 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
1900 >> WEIGHT_SHIFT);
1901 rgba[2] = (GLchan) (
1902 (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1903 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
1904 >> WEIGHT_SHIFT);
1905 rgba[3] = (GLchan) (
1906 (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1907 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
1908 >> WEIGHT_SHIFT);
1909 #endif
1910
1911 }
1912 }
1913
1914
1915
1916 static void
1917 sample_3d_nearest_mipmap_nearest(GLcontext *ctx,
1918 const struct gl_texture_object *tObj,
1919 GLuint n, const GLfloat texcoord[][4],
1920 const GLfloat lambda[], GLchan rgba[][4] )
1921 {
1922 GLuint i;
1923 for (i = 0; i < n; i++) {
1924 GLint level;
1925 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1926 sample_3d_nearest(ctx, tObj, tObj->Image[level], texcoord[i], rgba[i]);
1927 }
1928 }
1929
1930
1931 static void
1932 sample_3d_linear_mipmap_nearest(GLcontext *ctx,
1933 const struct gl_texture_object *tObj,
1934 GLuint n, const GLfloat texcoord[][4],
1935 const GLfloat lambda[], GLchan rgba[][4])
1936 {
1937 GLuint i;
1938 ASSERT(lambda != NULL);
1939 for (i = 0; i < n; i++) {
1940 GLint level;
1941 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
1942 sample_3d_linear(ctx, tObj, tObj->Image[level], texcoord[i], rgba[i]);
1943 }
1944 }
1945
1946
1947 static void
1948 sample_3d_nearest_mipmap_linear(GLcontext *ctx,
1949 const struct gl_texture_object *tObj,
1950 GLuint n, const GLfloat texcoord[][4],
1951 const GLfloat lambda[], GLchan rgba[][4])
1952 {
1953 GLuint i;
1954 ASSERT(lambda != NULL);
1955 for (i = 0; i < n; i++) {
1956 GLint level;
1957 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1958 if (level >= tObj->_MaxLevel) {
1959 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel],
1960 texcoord[i], rgba[i]);
1961 }
1962 else {
1963 GLchan t0[4], t1[4]; /* texels */
1964 const GLfloat f = FRAC(lambda[i]);
1965 sample_3d_nearest(ctx, tObj, tObj->Image[level ], texcoord[i], t0);
1966 sample_3d_nearest(ctx, tObj, tObj->Image[level+1], texcoord[i], t1);
1967 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1968 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1969 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1970 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1971 }
1972 }
1973 }
1974
1975
1976 static void
1977 sample_3d_linear_mipmap_linear(GLcontext *ctx,
1978 const struct gl_texture_object *tObj,
1979 GLuint n, const GLfloat texcoord[][4],
1980 const GLfloat lambda[], GLchan rgba[][4])
1981 {
1982 GLuint i;
1983 ASSERT(lambda != NULL);
1984 for (i = 0; i < n; i++) {
1985 GLint level;
1986 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
1987 if (level >= tObj->_MaxLevel) {
1988 sample_3d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel],
1989 texcoord[i], rgba[i]);
1990 }
1991 else {
1992 GLchan t0[4], t1[4]; /* texels */
1993 const GLfloat f = FRAC(lambda[i]);
1994 sample_3d_linear(ctx, tObj, tObj->Image[level ], texcoord[i], t0);
1995 sample_3d_linear(ctx, tObj, tObj->Image[level+1], texcoord[i], t1);
1996 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1997 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1998 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1999 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
2000 }
2001 }
2002 }
2003
2004
2005 static void
2006 sample_nearest_3d(GLcontext *ctx, GLuint texUnit,
2007 const struct gl_texture_object *tObj, GLuint n,
2008 const GLfloat texcoords[][4], const GLfloat lambda[],
2009 GLchan rgba[][4])
2010 {
2011 GLuint i;
2012 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
2013 (void) lambda;
2014 for (i=0;i<n;i++) {
2015 sample_3d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
2016 }
2017 }
2018
2019
2020
2021 static void
2022 sample_linear_3d( GLcontext *ctx, GLuint texUnit,
2023 const struct gl_texture_object *tObj, GLuint n,
2024 const GLfloat texcoords[][4],
2025 const GLfloat lambda[], GLchan rgba[][4] )
2026 {
2027 GLuint i;
2028 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
2029 (void) lambda;
2030 for (i=0;i<n;i++) {
2031 sample_3d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
2032 }
2033 }
2034
2035
2036 /*
2037 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
2038 * return a texture sample.
2039 */
2040 static void
2041 sample_lambda_3d( GLcontext *ctx, GLuint texUnit,
2042 const struct gl_texture_object *tObj, GLuint n,
2043 const GLfloat texcoords[][4], const GLfloat lambda[],
2044 GLchan rgba[][4] )
2045 {
2046 GLuint minStart, minEnd; /* texels with minification */
2047 GLuint magStart, magEnd; /* texels with magnification */
2048 GLuint i;
2049
2050 ASSERT(lambda != NULL);
2051 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
2052 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
2053
2054 if (minStart < minEnd) {
2055 /* do the minified texels */
2056 GLuint m = minEnd - minStart;
2057 switch (tObj->MinFilter) {
2058 case GL_NEAREST:
2059 for (i = minStart; i < minEnd; i++)
2060 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
2061 texcoords[i], rgba[i]);
2062 break;
2063 case GL_LINEAR:
2064 for (i = minStart; i < minEnd; i++)
2065 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
2066 texcoords[i], rgba[i]);
2067 break;
2068 case GL_NEAREST_MIPMAP_NEAREST:
2069 sample_3d_nearest_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
2070 lambda + minStart, rgba + minStart);
2071 break;
2072 case GL_LINEAR_MIPMAP_NEAREST:
2073 sample_3d_linear_mipmap_nearest(ctx, tObj, m, texcoords + minStart,
2074 lambda + minStart, rgba + minStart);
2075 break;
2076 case GL_NEAREST_MIPMAP_LINEAR:
2077 sample_3d_nearest_mipmap_linear(ctx, tObj, m, texcoords + minStart,
2078 lambda + minStart, rgba + minStart);
2079 break;
2080 case GL_LINEAR_MIPMAP_LINEAR:
2081 sample_3d_linear_mipmap_linear(ctx, tObj, m, texcoords + minStart,
2082 lambda + minStart, rgba + minStart);
2083 break;
2084 default:
2085 _mesa_problem(ctx, "Bad min filter in sample_3d_texture");
2086 return;
2087 }
2088 }
2089
2090 if (magStart < magEnd) {
2091 /* do the magnified texels */
2092 switch (tObj->MagFilter) {
2093 case GL_NEAREST:
2094 for (i = magStart; i < magEnd; i++)
2095 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
2096 texcoords[i], rgba[i]);
2097 break;
2098 case GL_LINEAR:
2099 for (i = magStart; i < magEnd; i++)
2100 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
2101 texcoords[i], rgba[i]);
2102 break;
2103 default:
2104 _mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
2105 return;
2106 }
2107 }
2108 }
2109
2110
2111 /**********************************************************************/
2112 /* Texture Cube Map Sampling Functions */
2113 /**********************************************************************/
2114
2115 /*
2116 * Choose one of six sides of a texture cube map given the texture
2117 * coord (rx,ry,rz). Return pointer to corresponding array of texture
2118 * images.
2119 */
2120 static const struct gl_texture_image **
2121 choose_cube_face(const struct gl_texture_object *texObj,
2122 const GLfloat texcoord[4], GLfloat newCoord[4])
2123 {
2124 /*
2125 major axis
2126 direction target sc tc ma
2127 ---------- ------------------------------- --- --- ---
2128 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
2129 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
2130 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
2131 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
2132 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
2133 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
2134 */
2135 const GLfloat rx = texcoord[0];
2136 const GLfloat ry = texcoord[1];
2137 const GLfloat rz = texcoord[2];
2138 const struct gl_texture_image **imgArray;
2139 const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
2140 GLfloat sc, tc, ma;
2141
2142 if (arx > ary && arx > arz) {
2143 if (rx >= 0.0F) {
2144 imgArray = (const struct gl_texture_image **) texObj->Image;
2145 sc = -rz;
2146 tc = -ry;
2147 ma = arx;
2148 }
2149 else {
2150 imgArray = (const struct gl_texture_image **) texObj->NegX;
2151 sc = rz;
2152 tc = -ry;
2153 ma = arx;
2154 }
2155 }
2156 else if (ary > arx && ary > arz) {
2157 if (ry >= 0.0F) {
2158 imgArray = (const struct gl_texture_image **) texObj->PosY;
2159 sc = rx;
2160 tc = rz;
2161 ma = ary;
2162 }
2163 else {
2164 imgArray = (const struct gl_texture_image **) texObj->NegY;
2165 sc = rx;
2166 tc = -rz;
2167 ma = ary;
2168 }
2169 }
2170 else {
2171 if (rz > 0.0F) {
2172 imgArray = (const struct gl_texture_image **) texObj->PosZ;
2173 sc = rx;
2174 tc = -ry;
2175 ma = arz;
2176 }
2177 else {
2178 imgArray = (const struct gl_texture_image **) texObj->NegZ;
2179 sc = -rx;
2180 tc = -ry;
2181 ma = arz;
2182 }
2183 }
2184
2185 newCoord[0] = ( sc / ma + 1.0F ) * 0.5F;
2186 newCoord[1] = ( tc / ma + 1.0F ) * 0.5F;
2187 return imgArray;
2188 }
2189
2190
2191 static void
2192 sample_nearest_cube(GLcontext *ctx, GLuint texUnit,
2193 const struct gl_texture_object *tObj, GLuint n,
2194 const GLfloat texcoords[][4], const GLfloat lambda[],
2195 GLchan rgba[][4])
2196 {
2197 GLuint i;
2198 (void) lambda;
2199 for (i = 0; i < n; i++) {
2200 const struct gl_texture_image **images;
2201 GLfloat newCoord[4];
2202 images = choose_cube_face(tObj, texcoords[i], newCoord);
2203 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
2204 newCoord, rgba[i]);
2205 }
2206 }
2207
2208
2209 static void
2210 sample_linear_cube(GLcontext *ctx, GLuint texUnit,
2211 const struct gl_texture_object *tObj, GLuint n,
2212 const GLfloat texcoords[][4],
2213 const GLfloat lambda[], GLchan rgba[][4])
2214 {
2215 GLuint i;
2216 (void) lambda;
2217 for (i = 0; i < n; i++) {
2218 const struct gl_texture_image **images;
2219 GLfloat newCoord[4];
2220 images = choose_cube_face(tObj, texcoords[i], newCoord);
2221 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
2222 newCoord, rgba[i]);
2223 }
2224 }
2225
2226
2227 static void
2228 sample_cube_nearest_mipmap_nearest(GLcontext *ctx, GLuint texUnit,
2229 const struct gl_texture_object *tObj,
2230 GLuint n, const GLfloat texcoord[][4],
2231 const GLfloat lambda[], GLchan rgba[][4])
2232 {
2233 GLuint i;
2234 ASSERT(lambda != NULL);
2235 for (i = 0; i < n; i++) {
2236 const struct gl_texture_image **images;
2237 GLfloat newCoord[4];
2238 GLint level;
2239 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
2240 images = choose_cube_face(tObj, texcoord[i], newCoord);
2241 sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]);
2242 }
2243 }
2244
2245
2246 static void
2247 sample_cube_linear_mipmap_nearest(GLcontext *ctx, GLuint texUnit,
2248 const struct gl_texture_object *tObj,
2249 GLuint n, const GLfloat texcoord[][4],
2250 const GLfloat lambda[], GLchan rgba[][4])
2251 {
2252 GLuint i;
2253 ASSERT(lambda != NULL);
2254 for (i = 0; i < n; i++) {
2255 const struct gl_texture_image **images;
2256 GLfloat newCoord[4];
2257 GLint level;
2258 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
2259 images = choose_cube_face(tObj, texcoord[i], newCoord);
2260 sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]);
2261 }
2262 }
2263
2264
2265 static void
2266 sample_cube_nearest_mipmap_linear(GLcontext *ctx, GLuint texUnit,
2267 const struct gl_texture_object *tObj,
2268 GLuint n, const GLfloat texcoord[][4],
2269 const GLfloat lambda[], GLchan rgba[][4])
2270 {
2271 GLuint i;
2272 ASSERT(lambda != NULL);
2273 for (i = 0; i < n; i++) {
2274 const struct gl_texture_image **images;
2275 GLfloat newCoord[4];
2276 GLint level;
2277 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
2278 images = choose_cube_face(tObj, texcoord[i], newCoord);
2279 if (level >= tObj->_MaxLevel) {
2280 sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel],
2281 newCoord, rgba[i]);
2282 }
2283 else {
2284 GLchan t0[4], t1[4]; /* texels */
2285 const GLfloat f = FRAC(lambda[i]);
2286 sample_2d_nearest(ctx, tObj, images[level ], newCoord, t0);
2287 sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1);
2288 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
2289 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
2290 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
2291 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
2292 }
2293 }
2294 }
2295
2296
2297 static void
2298 sample_cube_linear_mipmap_linear(GLcontext *ctx, GLuint texUnit,
2299 const struct gl_texture_object *tObj,
2300 GLuint n, const GLfloat texcoord[][4],
2301 const GLfloat lambda[], GLchan rgba[][4])
2302 {
2303 GLuint i;
2304 ASSERT(lambda != NULL);
2305 for (i = 0; i < n; i++) {
2306 const struct gl_texture_image **images;
2307 GLfloat newCoord[4];
2308 GLint level;
2309 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
2310 images = choose_cube_face(tObj, texcoord[i], newCoord);
2311 if (level >= tObj->_MaxLevel) {
2312 sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel],
2313 newCoord, rgba[i]);
2314 }
2315 else {
2316 GLchan t0[4], t1[4];
2317 const GLfloat f = FRAC(lambda[i]);
2318 sample_2d_linear(ctx, tObj, images[level ], newCoord, t0);
2319 sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1);
2320 rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
2321 rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
2322 rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
2323 rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
2324 }
2325 }
2326 }
2327
2328
2329 static void
2330 sample_lambda_cube( GLcontext *ctx, GLuint texUnit,
2331 const struct gl_texture_object *tObj, GLuint n,
2332 const GLfloat texcoords[][4], const GLfloat lambda[],
2333 GLchan rgba[][4])
2334 {
2335 GLuint minStart, minEnd; /* texels with minification */
2336 GLuint magStart, magEnd; /* texels with magnification */
2337
2338 ASSERT(lambda != NULL);
2339 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
2340 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
2341
2342 if (minStart < minEnd) {
2343 /* do the minified texels */
2344 const GLuint m = minEnd - minStart;
2345 switch (tObj->MinFilter) {
2346 case GL_NEAREST:
2347 sample_nearest_cube(ctx, texUnit, tObj, m, texcoords + minStart,
2348 lambda + minStart, rgba + minStart);
2349 break;
2350 case GL_LINEAR:
2351 sample_linear_cube(ctx, texUnit, tObj, m, texcoords + minStart,
2352 lambda + minStart, rgba + minStart);
2353 break;
2354 case GL_NEAREST_MIPMAP_NEAREST:
2355 sample_cube_nearest_mipmap_nearest(ctx, texUnit, tObj, m,
2356 texcoords + minStart,
2357 lambda + minStart, rgba + minStart);
2358 break;
2359 case GL_LINEAR_MIPMAP_NEAREST:
2360 sample_cube_linear_mipmap_nearest(ctx, texUnit, tObj, m,
2361 texcoords + minStart,
2362 lambda + minStart, rgba + minStart);
2363 break;
2364 case GL_NEAREST_MIPMAP_LINEAR:
2365 sample_cube_nearest_mipmap_linear(ctx, texUnit, tObj, m,
2366 texcoords + minStart,
2367 lambda + minStart, rgba + minStart);
2368 break;
2369 case GL_LINEAR_MIPMAP_LINEAR:
2370 sample_cube_linear_mipmap_linear(ctx, texUnit, tObj, m,
2371 texcoords + minStart,
2372 lambda + minStart, rgba + minStart);
2373 break;
2374 default:
2375 _mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
2376 }
2377 }
2378
2379 if (magStart < magEnd) {
2380 /* do the magnified texels */
2381 const GLuint m = magEnd - magStart;
2382 switch (tObj->MagFilter) {
2383 case GL_NEAREST:
2384 sample_nearest_cube(ctx, texUnit, tObj, m, texcoords + magStart,
2385 lambda + magStart, rgba + magStart);
2386 break;
2387 case GL_LINEAR:
2388 sample_linear_cube(ctx, texUnit, tObj, m, texcoords + magStart,
2389 lambda + magStart, rgba + magStart);
2390 break;
2391 default:
2392 _mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
2393 }
2394 }
2395 }
2396
2397
2398 /**********************************************************************/
2399 /* Texture Rectangle Sampling Functions */
2400 /**********************************************************************/
2401
2402 static void
2403 sample_nearest_rect(GLcontext *ctx, GLuint texUnit,
2404 const struct gl_texture_object *tObj, GLuint n,
2405 const GLfloat texcoords[][4], const GLfloat lambda[],
2406 GLchan rgba[][4])
2407 {
2408 const struct gl_texture_image *img = tObj->Image[0];
2409 const GLfloat width = (GLfloat) img->Width;
2410 const GLfloat height = (GLfloat) img->Height;
2411 const GLint width_minus_1 = img->Width - 1;
2412 const GLint height_minus_1 = img->Height - 1;
2413 GLuint i;
2414
2415 (void) texUnit;
2416 (void) lambda;
2417
2418 ASSERT(tObj->WrapS == GL_CLAMP ||
2419 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2420 tObj->WrapS == GL_CLAMP_TO_BORDER);
2421 ASSERT(tObj->WrapT == GL_CLAMP ||
2422 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2423 tObj->WrapT == GL_CLAMP_TO_BORDER);
2424 ASSERT(img->Format != GL_COLOR_INDEX);
2425
2426 /* XXX move Wrap mode tests outside of loops for common cases */
2427 for (i = 0; i < n; i++) {
2428 GLint row, col;
2429 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2430 if (tObj->WrapS == GL_CLAMP) {
2431 col = IFLOOR( CLAMP(texcoords[i][0], 0.0F, width) );
2432 }
2433 else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
2434 col = IFLOOR( CLAMP(texcoords[i][0], 0.5F, width - 0.5F) );
2435 }
2436 else {
2437 col = IFLOOR( CLAMP(texcoords[i][0], -0.5F, width + 0.5F) );
2438 }
2439 if (tObj->WrapT == GL_CLAMP) {
2440 row = IFLOOR( CLAMP(texcoords[i][1], 0.0F, height) );
2441 }
2442 else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
2443 row = IFLOOR( CLAMP(texcoords[i][1], 0.5F, height - 0.5F) );
2444 }
2445 else {
2446 row = IFLOOR( CLAMP(texcoords[i][1], -0.5F, height + 0.5F) );
2447 }
2448
2449 col = CLAMP(col, 0, width_minus_1);
2450 row = CLAMP(row, 0, height_minus_1);
2451
2452 img->FetchTexelc(img, col, row, 0, rgba[i]);
2453 }
2454 }
2455
2456
2457 static void
2458 sample_linear_rect(GLcontext *ctx, GLuint texUnit,
2459 const struct gl_texture_object *tObj, GLuint n,
2460 const GLfloat texcoords[][4],
2461 const GLfloat lambda[], GLchan rgba[][4])
2462 {
2463 const struct gl_texture_image *img = tObj->Image[0];
2464 const GLfloat width = (GLfloat) img->Width;
2465 const GLfloat height = (GLfloat) img->Height;
2466 const GLint width_minus_1 = img->Width - 1;
2467 const GLint height_minus_1 = img->Height - 1;
2468 GLuint i;
2469
2470 (void) texUnit;
2471 (void) lambda;
2472
2473 ASSERT(tObj->WrapS == GL_CLAMP ||
2474 tObj->WrapS == GL_CLAMP_TO_EDGE ||
2475 tObj->WrapS == GL_CLAMP_TO_BORDER);
2476 ASSERT(tObj->WrapT == GL_CLAMP ||
2477 tObj->WrapT == GL_CLAMP_TO_EDGE ||
2478 tObj->WrapT == GL_CLAMP_TO_BORDER);
2479 ASSERT(img->Format != GL_COLOR_INDEX);
2480
2481 /* XXX lots of opportunity for optimization in this loop */
2482 for (i = 0; i < n; i++) {
2483 GLfloat frow, fcol;
2484 GLint row0, col0, row1, col1;
2485 GLchan t00[4], t01[4], t10[4], t11[4];
2486 GLfloat a, b, w00, w01, w10, w11;
2487
2488 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2489 if (tObj->WrapS == GL_CLAMP) {
2490 fcol = CLAMP(texcoords[i][0], 0.0F, width);
2491 }
2492 else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
2493 fcol = CLAMP(texcoords[i][0], 0.5F, width - 0.5F);
2494 }
2495 else {
2496 fcol = CLAMP(texcoords[i][0], -0.5F, width + 0.5F);
2497 }
2498 if (tObj->WrapT == GL_CLAMP) {
2499 frow = CLAMP(texcoords[i][1], 0.0F, height);
2500 }
2501 else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
2502 frow = CLAMP(texcoords[i][1], 0.5F, height - 0.5F);
2503 }
2504 else {
2505 frow = CLAMP(texcoords[i][1], -0.5F, height + 0.5F);
2506 }
2507
2508 /* compute integer rows/columns */
2509 col0 = IFLOOR(fcol);
2510 col1 = col0 + 1;
2511 col0 = CLAMP(col0, 0, width_minus_1);
2512 col1 = CLAMP(col1, 0, width_minus_1);
2513 row0 = IFLOOR(frow);
2514 row1 = row0 + 1;
2515 row0 = CLAMP(row0, 0, height_minus_1);
2516 row1 = CLAMP(row1, 0, height_minus_1);
2517
2518 /* get four texel samples */
2519 img->FetchTexelc(img, col0, row0, 0, t00);
2520 img->FetchTexelc(img, col1, row0, 0, t10);
2521 img->FetchTexelc(img, col0, row1, 0, t01);
2522 img->FetchTexelc(img, col1, row1, 0, t11);
2523
2524 /* compute sample weights */
2525 a = FRAC(fcol);
2526 b = FRAC(frow);
2527 w00 = (1.0F-a) * (1.0F-b);
2528 w10 = a * (1.0F-b);
2529 w01 = (1.0F-a) * b ;
2530 w11 = a * b ;
2531
2532 /* compute weighted average of samples */
2533 rgba[i][0] =
2534 (GLchan) (w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]);
2535 rgba[i][1] =
2536 (GLchan) (w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]);
2537 rgba[i][2] =
2538 (GLchan) (w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]);
2539 rgba[i][3] =
2540 (GLchan) (w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]);
2541 }
2542 }
2543
2544
2545 static void
2546 sample_lambda_rect( GLcontext *ctx, GLuint texUnit,
2547 const struct gl_texture_object *tObj, GLuint n,
2548 const GLfloat texcoords[][4], const GLfloat lambda[],
2549 GLchan rgba[][4])
2550 {
2551 GLuint minStart, minEnd, magStart, magEnd;
2552
2553 /* We only need lambda to decide between minification and magnification.
2554 * There is no mipmapping with rectangular textures.
2555 */
2556 compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
2557 n, lambda, &minStart, &minEnd, &magStart, &magEnd);
2558
2559 if (minStart < minEnd) {
2560 if (tObj->MinFilter == GL_NEAREST) {
2561 sample_nearest_rect( ctx, texUnit, tObj, minEnd - minStart,
2562 texcoords + minStart, NULL, rgba + minStart);
2563 }
2564 else {
2565 sample_linear_rect( ctx, texUnit, tObj, minEnd - minStart,
2566 texcoords + minStart, NULL, rgba + minStart);
2567 }
2568 }
2569 if (magStart < magEnd) {
2570 if (tObj->MagFilter == GL_NEAREST) {
2571 sample_nearest_rect( ctx, texUnit, tObj, magEnd - magStart,
2572 texcoords + magStart, NULL, rgba + magStart);
2573 }
2574 else {
2575 sample_linear_rect( ctx, texUnit, tObj, magEnd - magStart,
2576 texcoords + magStart, NULL, rgba + magStart);
2577 }
2578 }
2579 }
2580
2581
2582
2583 /*
2584 * Sample a shadow/depth texture.
2585 */
2586 static void
2587 sample_depth_texture( GLcontext *ctx, GLuint unit,
2588 const struct gl_texture_object *tObj, GLuint n,
2589 const GLfloat texcoords[][4], const GLfloat lambda[],
2590 GLchan texel[][4] )
2591 {
2592 const GLint baseLevel = tObj->BaseLevel;
2593 const struct gl_texture_image *texImage = tObj->Image[baseLevel];
2594 const GLuint width = texImage->Width;
2595 const GLuint height = texImage->Height;
2596 GLchan ambient;
2597 GLenum function;
2598 GLchan result;
2599
2600 (void) unit;
2601
2602 ASSERT(tObj->Image[tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
2603 ASSERT(tObj->Target == GL_TEXTURE_1D ||
2604 tObj->Target == GL_TEXTURE_2D ||
2605 tObj->Target == GL_TEXTURE_RECTANGLE_NV);
2606
2607 UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
2608
2609 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2610
2611 /* XXX this could be precomputed and saved in the texture object */
2612 if (tObj->CompareFlag) {
2613 /* GL_SGIX_shadow */
2614 if (tObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2615 function = GL_LEQUAL;
2616 }
2617 else {
2618 ASSERT(tObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
2619 function = GL_GEQUAL;
2620 }
2621 }
2622 else if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
2623 /* GL_ARB_shadow */
2624 function = tObj->CompareFunc;
2625 }
2626 else {
2627 function = GL_NONE; /* pass depth through as grayscale */
2628 }
2629
2630 if (tObj->MagFilter == GL_NEAREST) {
2631 GLuint i;
2632 for (i = 0; i < n; i++) {
2633 GLfloat depthSample;
2634 GLint col, row;
2635 /* XXX fix for texture rectangle! */
2636 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
2637 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
2638 texImage->FetchTexelf(texImage, col, row, 0, &depthSample);
2639
2640 switch (function) {
2641 case GL_LEQUAL:
2642 result = (texcoords[i][2] <= depthSample) ? CHAN_MAX : ambient;
2643 break;
2644 case GL_GEQUAL:
2645 result = (texcoords[i][2] >= depthSample) ? CHAN_MAX : ambient;
2646 break;
2647 case GL_LESS:
2648 result = (texcoords[i][2] < depthSample) ? CHAN_MAX : ambient;
2649 break;
2650 case GL_GREATER:
2651 result = (texcoords[i][2] > depthSample) ? CHAN_MAX : ambient;
2652 break;
2653 case GL_EQUAL:
2654 result = (texcoords[i][2] == depthSample) ? CHAN_MAX : ambient;
2655 break;
2656 case GL_NOTEQUAL:
2657 result = (texcoords[i][2] != depthSample) ? CHAN_MAX : ambient;
2658 break;
2659 case GL_ALWAYS:
2660 result = CHAN_MAX;
2661 break;
2662 case GL_NEVER:
2663 result = ambient;
2664 break;
2665 case GL_NONE:
2666 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
2667 break;
2668 default:
2669 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
2670 return;
2671 }
2672
2673 switch (tObj->DepthMode) {
2674 case GL_LUMINANCE:
2675 texel[i][RCOMP] = result;
2676 texel[i][GCOMP] = result;
2677 texel[i][BCOMP] = result;
2678 texel[i][ACOMP] = CHAN_MAX;
2679 break;
2680 case GL_INTENSITY:
2681 texel[i][RCOMP] = result;
2682 texel[i][GCOMP] = result;
2683 texel[i][BCOMP] = result;
2684 texel[i][ACOMP] = result;
2685 break;
2686 case GL_ALPHA:
2687 texel[i][RCOMP] = 0;
2688 texel[i][GCOMP] = 0;
2689 texel[i][BCOMP] = 0;
2690 texel[i][ACOMP] = result;
2691 break;
2692 default:
2693 _mesa_problem(ctx, "Bad depth texture mode");
2694 }
2695 }
2696 }
2697 else {
2698 GLuint i;
2699 ASSERT(tObj->MagFilter == GL_LINEAR);
2700 for (i = 0; i < n; i++) {
2701 GLfloat depth00, depth01, depth10, depth11;
2702 GLint i0, i1, j0, j1;
2703 GLfloat u, v;
2704 GLuint useBorderTexel;
2705
2706 /* XXX fix for texture rectangle! */
2707 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
2708 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
2709
2710 useBorderTexel = 0;
2711 if (texImage->Border) {
2712 i0 += texImage->Border;
2713 i1 += texImage->Border;
2714 j0 += texImage->Border;
2715 j1 += texImage->Border;
2716 }
2717 else {
2718 if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
2719 if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
2720 if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
2721 if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
2722 }
2723
2724 /* get four depth samples from the texture */
2725 if (useBorderTexel & (I0BIT | J0BIT)) {
2726 depth00 = 1.0;
2727 }
2728 else {
2729 texImage->FetchTexelf(texImage, i0, j0, 0, &depth00);
2730 }
2731 if (useBorderTexel & (I1BIT | J0BIT)) {
2732 depth10 = 1.0;
2733 }
2734 else {
2735 texImage->FetchTexelf(texImage, i1, j0, 0, &depth10);
2736 }
2737 if (useBorderTexel & (I0BIT | J1BIT)) {
2738 depth01 = 1.0;
2739 }
2740 else {
2741 texImage->FetchTexelf(texImage, i0, j1, 0, &depth01);
2742 }
2743 if (useBorderTexel & (I1BIT | J1BIT)) {
2744 depth11 = 1.0;
2745 }
2746 else {
2747 texImage->FetchTexelf(texImage, i1, j1, 0, &depth11);
2748 }
2749
2750 if (0) {
2751 /* compute a single weighted depth sample and do one comparison */
2752 const GLfloat a = FRAC(u + 1.0F);
2753 const GLfloat b = FRAC(v + 1.0F);
2754 const GLfloat w00 = (1.0F - a) * (1.0F - b);
2755 const GLfloat w10 = ( a) * (1.0F - b);
2756 const GLfloat w01 = (1.0F - a) * ( b);
2757 const GLfloat w11 = ( a) * ( b);
2758 const GLfloat depthSample = w00 * depth00 + w10 * depth10
2759 + w01 * depth01 + w11 * depth11;
2760 if ((depthSample <= texcoords[i][2] && function == GL_LEQUAL) ||
2761 (depthSample >= texcoords[i][2] && function == GL_GEQUAL)) {
2762 result = ambient;
2763 }
2764 else {
2765 result = CHAN_MAX;
2766 }
2767 }
2768 else {
2769 /* Do four depth/R comparisons and compute a weighted result.
2770 * If this touches on somebody's I.P., I'll remove this code
2771 * upon request.
2772 */
2773 const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
2774 GLfloat luminance = CHAN_MAXF;
2775
2776 switch (function) {
2777 case GL_LEQUAL:
2778 if (depth00 <= texcoords[i][2]) luminance -= d;
2779 if (depth01 <= texcoords[i][2]) luminance -= d;
2780 if (depth10 <= texcoords[i][2]) luminance -= d;
2781 if (depth11 <= texcoords[i][2]) luminance -= d;
2782 result = (GLchan) luminance;
2783 break;
2784 case GL_GEQUAL:
2785 if (depth00 >= texcoords[i][2]) luminance -= d;
2786 if (depth01 >= texcoords[i][2]) luminance -= d;
2787 if (depth10 >= texcoords[i][2]) luminance -= d;
2788 if (depth11 >= texcoords[i][2]) luminance -= d;
2789 result = (GLchan) luminance;
2790 break;
2791 case GL_LESS:
2792 if (depth00 < texcoords[i][2]) luminance -= d;
2793 if (depth01 < texcoords[i][2]) luminance -= d;
2794 if (depth10 < texcoords[i][2]) luminance -= d;
2795 if (depth11 < texcoords[i][2]) luminance -= d;
2796 result = (GLchan) luminance;
2797 break;
2798 case GL_GREATER:
2799 if (depth00 > texcoords[i][2]) luminance -= d;
2800 if (depth01 > texcoords[i][2]) luminance -= d;
2801 if (depth10 > texcoords[i][2]) luminance -= d;
2802 if (depth11 > texcoords[i][2]) luminance -= d;
2803 result = (GLchan) luminance;
2804 break;
2805 case GL_EQUAL:
2806 if (depth00 == texcoords[i][2]) luminance -= d;
2807 if (depth01 == texcoords[i][2]) luminance -= d;
2808 if (depth10 == texcoords[i][2]) luminance -= d;
2809 if (depth11 == texcoords[i][2]) luminance -= d;
2810 result = (GLchan) luminance;
2811 break;
2812 case GL_NOTEQUAL:
2813 if (depth00 != texcoords[i][2]) luminance -= d;
2814 if (depth01 != texcoords[i][2]) luminance -= d;
2815 if (depth10 != texcoords[i][2]) luminance -= d;
2816 if (depth11 != texcoords[i][2]) luminance -= d;
2817 result = (GLchan) luminance;
2818 break;
2819 case GL_ALWAYS:
2820 result = 0;
2821 break;
2822 case GL_NEVER:
2823 result = CHAN_MAX;
2824 break;
2825 case GL_NONE:
2826 /* ordinary bilinear filtering */
2827 {
2828 const GLfloat a = FRAC(u + 1.0F);
2829 const GLfloat b = FRAC(v + 1.0F);
2830 const GLfloat w00 = (1.0F - a) * (1.0F - b);
2831 const GLfloat w10 = ( a) * (1.0F - b);
2832 const GLfloat w01 = (1.0F - a) * ( b);
2833 const GLfloat w11 = ( a) * ( b);
2834 const GLfloat depthSample = w00 * depth00 + w10 * depth10
2835 + w01 * depth01 + w11 * depth11;
2836 CLAMPED_FLOAT_TO_CHAN(result, depthSample);
2837 }
2838 break;
2839 default:
2840 _mesa_problem(ctx, "Bad compare func in sample_depth_texture");
2841 return;
2842 }
2843 }
2844
2845 switch (tObj->DepthMode) {
2846 case GL_LUMINANCE:
2847 texel[i][RCOMP] = result;
2848 texel[i][GCOMP] = result;
2849 texel[i][BCOMP] = result;
2850 texel[i][ACOMP] = CHAN_MAX;
2851 break;
2852 case GL_INTENSITY:
2853 texel[i][RCOMP] = result;
2854 texel[i][GCOMP] = result;
2855 texel[i][BCOMP] = result;
2856 texel[i][ACOMP] = result;
2857 break;
2858 case GL_ALPHA:
2859 texel[i][RCOMP] = 0;
2860 texel[i][GCOMP] = 0;
2861 texel[i][BCOMP] = 0;
2862 texel[i][ACOMP] = result;
2863 break;
2864 default:
2865 _mesa_problem(ctx, "Bad depth texture mode");
2866 }
2867 } /* for */
2868 } /* if filter */
2869 }
2870
2871
2872 #if 0
2873 /*
2874 * Experimental depth texture sampling function.
2875 */
2876 static void
2877 sample_depth_texture2(const GLcontext *ctx,
2878 const struct gl_texture_unit *texUnit,
2879 GLuint n, const GLfloat texcoords[][4],
2880 GLchan texel[][4])
2881 {
2882 const struct gl_texture_object *texObj = texUnit->_Current;
2883 const GLint baseLevel = texObj->BaseLevel;
2884 const struct gl_texture_image *texImage = texObj->Image[baseLevel];
2885 const GLuint width = texImage->Width;
2886 const GLuint height = texImage->Height;
2887 GLchan ambient;
2888 GLboolean lequal, gequal;
2889
2890 if (texObj->Target != GL_TEXTURE_2D) {
2891 _mesa_problem(ctx, "only 2-D depth textures supported at this time");
2892 return;
2893 }
2894
2895 if (texObj->MinFilter != texObj->MagFilter) {
2896 _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
2897 return;
2898 }
2899
2900 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2901 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2902 * isn't a depth texture.
2903 */
2904 if (texImage->Format != GL_DEPTH_COMPONENT) {
2905 _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2906 return;
2907 }
2908
2909 UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
2910
2911 if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2912 lequal = GL_TRUE;
2913 gequal = GL_FALSE;
2914 }
2915 else {
2916 lequal = GL_FALSE;
2917 gequal = GL_TRUE;
2918 }
2919
2920 {
2921 GLuint i;
2922 for (i = 0; i < n; i++) {
2923 const GLint K = 3;
2924 GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
2925 GLfloat w;
2926 GLchan lum;
2927 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0],
2928 width, col);
2929 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1],
2930 height, row);
2931
2932 imin = col - K;
2933 imax = col + K;
2934 jmin = row - K;
2935 jmax = row + K;
2936
2937 if (imin < 0) imin = 0;
2938 if (imax >= width) imax = width - 1;
2939 if (jmin < 0) jmin = 0;
2940 if (jmax >= height) jmax = height - 1;
2941
2942 samples = (imax - imin + 1) * (jmax - jmin + 1);
2943 count = 0;
2944 for (jj = jmin; jj <= jmax; jj++) {
2945 for (ii = imin; ii <= imax; ii++) {
2946 GLfloat depthSample;
2947 texImage->FetchTexelf(texImage, ii, jj, 0, &depthSample);
2948 if ((depthSample <= r[i] && lequal) ||
2949 (depthSample >= r[i] && gequal)) {
2950 count++;
2951 }
2952 }
2953 }
2954
2955 w = (GLfloat) count / (GLfloat) samples;
2956 w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
2957 lum = (GLint) w;
2958
2959 texel[i][RCOMP] = lum;
2960 texel[i][GCOMP] = lum;
2961 texel[i][BCOMP] = lum;
2962 texel[i][ACOMP] = CHAN_MAX;
2963 }
2964 }
2965 }
2966 #endif
2967
2968
2969 /**
2970 * We use this function when a texture object is in an "incomplete" state.
2971 * When a fragment program attempts to sample an incomplete texture we
2972 * return black.
2973 * Note: frag progs don't observe texture enable/disable flags.
2974 */
2975 static void
2976 null_sample_func( GLcontext *ctx, GLuint texUnit,
2977 const struct gl_texture_object *tObj, GLuint n,
2978 const GLfloat texcoords[][4], const GLfloat lambda[],
2979 GLchan rgba[][4])
2980 {
2981 (void) ctx;
2982 (void) texUnit;
2983 (void) tObj;
2984 (void) texcoords;
2985 (void) lambda;
2986 _mesa_bzero(rgba, n * 4 * sizeof(GLchan));
2987 }
2988
2989
2990
2991 /**
2992 * Setup the texture sampling function for this texture object.
2993 */
2994 texture_sample_func
2995 _swrast_choose_texture_sample_func( GLcontext *ctx,
2996 const struct gl_texture_object *t )
2997 {
2998 const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
2999 const GLenum format = t->Image[t->BaseLevel]->Format;
3000
3001 if (!t->Complete) {
3002 return &null_sample_func;
3003 }
3004
3005 switch (t->Target) {
3006 case GL_TEXTURE_1D:
3007 if (format == GL_DEPTH_COMPONENT) {
3008 return &sample_depth_texture;
3009 }
3010 else if (needLambda) {
3011 return &sample_lambda_1d;
3012 }
3013 else if (t->MinFilter == GL_LINEAR) {
3014 return &sample_linear_1d;
3015 }
3016 else {
3017 ASSERT(t->MinFilter == GL_NEAREST);
3018 return &sample_nearest_1d;
3019 }
3020 break;
3021 case GL_TEXTURE_2D:
3022 if (format == GL_DEPTH_COMPONENT) {
3023 return &sample_depth_texture;
3024 }
3025 else if (needLambda) {
3026 return &sample_lambda_2d;
3027 }
3028 else if (t->MinFilter == GL_LINEAR) {
3029 return &sample_linear_2d;
3030 }
3031 else {
3032 GLint baseLevel = t->BaseLevel;
3033 ASSERT(t->MinFilter == GL_NEAREST);
3034 if (t->WrapS == GL_REPEAT &&
3035 t->WrapT == GL_REPEAT &&
3036 t->_IsPowerOfTwo &&
3037 t->Image[baseLevel]->Border == 0 &&
3038 t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
3039 return &opt_sample_rgb_2d;
3040 }
3041 else if (t->WrapS == GL_REPEAT &&
3042 t->WrapT == GL_REPEAT &&
3043 t->_IsPowerOfTwo &&
3044 t->Image[baseLevel]->Border == 0 &&
3045 t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
3046 return &opt_sample_rgba_2d;
3047 }
3048 else {
3049 return &sample_nearest_2d;
3050 }
3051 }
3052 break;
3053 case GL_TEXTURE_3D:
3054 if (needLambda) {
3055 return &sample_lambda_3d;
3056 }
3057 else if (t->MinFilter == GL_LINEAR) {
3058 return &sample_linear_3d;
3059 }
3060 else {
3061 ASSERT(t->MinFilter == GL_NEAREST);
3062 return &sample_nearest_3d;
3063 }
3064 break;
3065 case GL_TEXTURE_CUBE_MAP:
3066 if (needLambda) {
3067 return &sample_lambda_cube;
3068 }
3069 else if (t->MinFilter == GL_LINEAR) {
3070 return &sample_linear_cube;
3071 }
3072 else {
3073 ASSERT(t->MinFilter == GL_NEAREST);
3074 return &sample_nearest_cube;
3075 }
3076 break;
3077 case GL_TEXTURE_RECTANGLE_NV:
3078 if (needLambda) {
3079 return &sample_lambda_rect;
3080 }
3081 else if (t->MinFilter == GL_LINEAR) {
3082 return &sample_linear_rect;
3083 }
3084 else {
3085 ASSERT(t->MinFilter == GL_NEAREST);
3086 return &sample_nearest_rect;
3087 }
3088 break;
3089 default:
3090 _mesa_problem(ctx,
3091 "invalid target in _swrast_choose_texture_sample_func");
3092 return &null_sample_func;
3093 }
3094 }
3095
3096
3097 #define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
3098 #define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
3099
3100
3101 /**
3102 * Do texture application for GL_ARB/EXT_texture_env_combine.
3103 * This function also supports GL_{EXT,ARB}_texture_env_dot3 and
3104 * GL_ATI_texture_env_combine3
3105 *
3106 * \param ctx rendering context
3107 * \param textureUnit the texture unit to apply
3108 * \param n number of fragments to process (span width)
3109 * \param primary_rgba incoming fragment color array
3110 * \param texelBuffer pointer to texel colors for all texture units
3111 *
3112 * \param rgba incoming colors, which get modified here
3113 */
3114 static INLINE void
3115 texture_combine( const GLcontext *ctx, GLuint unit, GLuint n,
3116 CONST GLchan (*primary_rgba)[4],
3117 CONST GLchan *texelBuffer,
3118 GLchan (*rgba)[4] )
3119 {
3120 const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
3121 const GLchan (*argRGB [3])[4];
3122 const GLchan (*argA [3])[4];
3123 const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
3124 const GLuint Ashift = textureUnit->CombineScaleShiftA;
3125 #if CHAN_TYPE == GL_FLOAT
3126 const GLchan RGBmult = (GLfloat) (1 << RGBshift);
3127 const GLchan Amult = (GLfloat) (1 << Ashift);
3128 static const GLchan one[4] = { 1.0, 1.0, 1.0, 1.0 };
3129 static const GLchan zero[4] = { 0.0, 0.0, 0.0, 0.0 };
3130 #else
3131 const GLint half = (CHAN_MAX + 1) / 2;
3132 static const GLchan one[4] = { CHAN_MAX, CHAN_MAX, CHAN_MAX, CHAN_MAX };
3133 static const GLchan zero[4] = { 0, 0, 0, 0 };
3134 #endif
3135 GLuint i, j;
3136 GLuint numColorArgs;
3137 GLuint numAlphaArgs;
3138
3139 /* GLchan ccolor[3][4]; */
3140 DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4); /* mac 32k limitation */
3141 CHECKARRAY(ccolor, return); /* mac 32k limitation */
3142
3143 ASSERT(ctx->Extensions.EXT_texture_env_combine ||
3144 ctx->Extensions.ARB_texture_env_combine);
3145 ASSERT(SWRAST_CONTEXT(ctx)->_AnyTextureCombine);
3146
3147
3148 /*
3149 printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
3150 textureUnit->CombineModeRGB,
3151 textureUnit->CombineModeA,
3152 textureUnit->CombineSourceRGB[0],
3153 textureUnit->CombineSourceA[0],
3154 textureUnit->CombineSourceRGB[1],
3155 textureUnit->CombineSourceA[1]);
3156 */
3157
3158 /*
3159 * Do operand setup for up to 3 operands. Loop over the terms.
3160 */
3161 switch (textureUnit->CombineModeRGB) {
3162 case GL_REPLACE:
3163 numColorArgs = 1;
3164 break;
3165 case GL_MODULATE:
3166 case GL_ADD:
3167 case GL_ADD_SIGNED:
3168 case GL_SUBTRACT:
3169 case GL_DOT3_RGB:
3170 case GL_DOT3_RGBA:
3171 case GL_DOT3_RGB_EXT:
3172 case GL_DOT3_RGBA_EXT:
3173 numColorArgs = 2;
3174 break;
3175 case GL_INTERPOLATE:
3176 case GL_MODULATE_ADD_ATI:
3177 case GL_MODULATE_SIGNED_ADD_ATI:
3178 case GL_MODULATE_SUBTRACT_ATI:
3179 numColorArgs = 3;
3180 break;
3181 default:
3182 numColorArgs = 0;
3183 ASSERT(0);
3184 break;
3185 }
3186
3187 switch (textureUnit->CombineModeA) {
3188 case GL_REPLACE:
3189 numAlphaArgs = 1;
3190 break;
3191 case GL_MODULATE:
3192 case GL_ADD:
3193 case GL_ADD_SIGNED:
3194 case GL_SUBTRACT:
3195 numAlphaArgs = 2;
3196 break;
3197 case GL_INTERPOLATE:
3198 case GL_MODULATE_ADD_ATI:
3199 case GL_MODULATE_SIGNED_ADD_ATI:
3200 case GL_MODULATE_SUBTRACT_ATI:
3201 numAlphaArgs = 3;
3202 break;
3203 default:
3204 numAlphaArgs = 0;
3205 ASSERT(0);
3206 break;
3207 }
3208
3209 for (j = 0; j < numColorArgs; j++) {
3210 const GLenum srcRGB = textureUnit->CombineSourceRGB[j];
3211
3212
3213 switch (srcRGB) {
3214 case GL_TEXTURE:
3215 argRGB[j] = (const GLchan (*)[4])
3216 (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
3217 break;
3218 case GL_PRIMARY_COLOR:
3219 argRGB[j] = primary_rgba;
3220 break;
3221 case GL_PREVIOUS:
3222 argRGB[j] = (const GLchan (*)[4]) rgba;
3223 break;
3224 case GL_CONSTANT:
3225 {
3226 GLchan (*c)[4] = ccolor[j];
3227 GLchan red, green, blue, alpha;
3228 UNCLAMPED_FLOAT_TO_CHAN(red, textureUnit->EnvColor[0]);
3229 UNCLAMPED_FLOAT_TO_CHAN(green, textureUnit->EnvColor[1]);
3230 UNCLAMPED_FLOAT_TO_CHAN(blue, textureUnit->EnvColor[2]);
3231 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
3232 for (i = 0; i < n; i++) {
3233 c[i][RCOMP] = red;
3234 c[i][GCOMP] = green;
3235 c[i][BCOMP] = blue;
3236 c[i][ACOMP] = alpha;
3237 }
3238 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
3239 }
3240 break;
3241 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
3242 */
3243 case GL_ZERO:
3244 argRGB[j] = & zero;
3245 break;
3246 case GL_ONE:
3247 argRGB[j] = & one;
3248 break;
3249 default:
3250 /* ARB_texture_env_crossbar source */
3251 {
3252 const GLuint srcUnit = srcRGB - GL_TEXTURE0;
3253 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
3254 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
3255 return;
3256 argRGB[j] = (const GLchan (*)[4])
3257 (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
3258 }
3259 }
3260
3261 if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
3262 const GLchan (*src)[4] = argRGB[j];
3263 GLchan (*dst)[4] = ccolor[j];
3264
3265 /* point to new arg[j] storage */
3266 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
3267
3268 if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
3269 for (i = 0; i < n; i++) {
3270 dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
3271 dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
3272 dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
3273 }
3274 }
3275 else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) {
3276 for (i = 0; i < n; i++) {
3277 dst[i][RCOMP] = src[i][ACOMP];
3278 dst[i][GCOMP] = src[i][ACOMP];
3279 dst[i][BCOMP] = src[i][ACOMP];
3280 }
3281 }
3282 else {
3283 ASSERT(textureUnit->CombineOperandRGB[j] ==GL_ONE_MINUS_SRC_ALPHA);
3284 for (i = 0; i < n; i++) {
3285 dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
3286 dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
3287 dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
3288 }
3289 }
3290 }
3291 }
3292
3293
3294 for (j = 0; j < numAlphaArgs; j++) {
3295 const GLenum srcA = textureUnit->CombineSourceA[j];
3296
3297 switch (srcA) {
3298 case GL_TEXTURE:
3299 argA[j] = (const GLchan (*)[4])
3300 (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
3301 break;
3302 case GL_PRIMARY_COLOR:
3303 argA[j] = primary_rgba;
3304 break;
3305 case GL_PREVIOUS:
3306 argA[j] = (const GLchan (*)[4]) rgba;
3307 break;
3308 case GL_CONSTANT:
3309 {
3310 GLchan alpha, (*c)[4] = ccolor[j];
3311 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
3312 for (i = 0; i < n; i++)
3313 c[i][ACOMP] = alpha;
3314 argA[j] = (const GLchan (*)[4]) ccolor[j];
3315 }
3316 break;
3317 /* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
3318 */
3319 case GL_ZERO:
3320 argA[j] = & zero;
3321 break;
3322 case GL_ONE:
3323 argA[j] = & one;
3324 break;
3325 default:
3326 /* ARB_texture_env_crossbar source */
3327 {
3328 const GLuint srcUnit = srcA - GL_TEXTURE0;
3329 ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
3330 if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
3331 return;
3332 argA[j] = (const GLchan (*)[4])
3333 (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
3334 }
3335 }
3336
3337 if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
3338 const GLchan (*src)[4] = argA[j];
3339 GLchan (*dst)[4] = ccolor[j];
3340 argA[j] = (const GLchan (*)[4]) ccolor[j];
3341 for (i = 0; i < n; i++) {
3342 dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
3343 }
3344 }
3345 }
3346
3347 /*
3348 * Do the texture combine.
3349 */
3350 switch (textureUnit->CombineModeRGB) {
3351 case GL_REPLACE:
3352 {
3353 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3354 if (RGBshift) {
3355 for (i = 0; i < n; i++) {
3356 #if CHAN_TYPE == GL_FLOAT
3357 rgba[i][RCOMP] = arg0[i][RCOMP] * RGBmult;
3358 rgba[i][GCOMP] = arg0[i][GCOMP] * RGBmult;
3359 rgba[i][BCOMP] = arg0[i][BCOMP] * RGBmult;
3360 #else
3361 GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
3362 GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
3363 GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
3364 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
3365 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
3366 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
3367 #endif
3368 }
3369 }
3370 else {
3371 for (i = 0; i < n; i++) {
3372 rgba[i][RCOMP] = arg0[i][RCOMP];
3373 rgba[i][GCOMP] = arg0[i][GCOMP];
3374 rgba[i][BCOMP] = arg0[i][BCOMP];
3375 }
3376 }
3377 }
3378 break;
3379 case GL_MODULATE:
3380 {
3381 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3382 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3383 #if CHAN_TYPE != GL_FLOAT
3384 const GLint shift = CHAN_BITS - RGBshift;
3385 #endif
3386 for (i = 0; i < n; i++) {
3387 #if CHAN_TYPE == GL_FLOAT
3388 rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * RGBmult;
3389 rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * RGBmult;
3390 rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * RGBmult;
3391 #else
3392 GLuint r = PROD(arg0[i][RCOMP], arg1[i][RCOMP]) >> shift;
3393 GLuint g = PROD(arg0[i][GCOMP], arg1[i][GCOMP]) >> shift;
3394 GLuint b = PROD(arg0[i][BCOMP], arg1[i][BCOMP]) >> shift;
3395 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3396 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3397 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3398 #endif
3399 }
3400 }
3401 break;
3402 case GL_ADD:
3403 {
3404 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3405 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3406 for (i = 0; i < n; i++) {
3407 #if CHAN_TYPE == GL_FLOAT
3408 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * RGBmult;
3409 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * RGBmult;
3410 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * RGBmult;
3411 #else
3412 GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
3413 GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
3414 GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
3415 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3416 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3417 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3418 #endif
3419 }
3420 }
3421 break;
3422 case GL_ADD_SIGNED:
3423 {
3424 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3425 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3426 for (i = 0; i < n; i++) {
3427 #if CHAN_TYPE == GL_FLOAT
3428 rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5) * RGBmult;
3429 rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5) * RGBmult;
3430 rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5) * RGBmult;
3431 #else
3432 GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] -half;
3433 GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] -half;
3434 GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] -half;
3435 r = (r < 0) ? 0 : r << RGBshift;
3436 g = (g < 0) ? 0 : g << RGBshift;
3437 b = (b < 0) ? 0 : b << RGBshift;
3438 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3439 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3440 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3441 #endif
3442 }
3443 }
3444 break;
3445 case GL_INTERPOLATE:
3446 {
3447 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3448 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3449 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3450 #if CHAN_TYPE != GL_FLOAT
3451 const GLint shift = CHAN_BITS - RGBshift;
3452 #endif
3453 for (i = 0; i < n; i++) {
3454 #if CHAN_TYPE == GL_FLOAT
3455 rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
3456 arg1[i][RCOMP] * (CHAN_MAXF - arg2[i][RCOMP])) * RGBmult;
3457 rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
3458 arg1[i][GCOMP] * (CHAN_MAXF - arg2[i][GCOMP])) * RGBmult;
3459 rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
3460 arg1[i][BCOMP] * (CHAN_MAXF - arg2[i][BCOMP])) * RGBmult;
3461 #else
3462 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3463 + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
3464 >> shift;
3465 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3466 + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
3467 >> shift;
3468 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3469 + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
3470 >> shift;
3471 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3472 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3473 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3474 #endif
3475 }
3476 }
3477 break;
3478 case GL_SUBTRACT:
3479 {
3480 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3481 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3482 for (i = 0; i < n; i++) {
3483 #if CHAN_TYPE == GL_FLOAT
3484 rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * RGBmult;
3485 rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * RGBmult;
3486 rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * RGBmult;
3487 #else
3488 GLint r = ((GLint) arg0[i][RCOMP] - (GLint) arg1[i][RCOMP]) << RGBshift;
3489 GLint g = ((GLint) arg0[i][GCOMP] - (GLint) arg1[i][GCOMP]) << RGBshift;
3490 GLint b = ((GLint) arg0[i][BCOMP] - (GLint) arg1[i][BCOMP]) << RGBshift;
3491 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3492 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3493 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3494 #endif
3495 }
3496 }
3497 break;
3498 case GL_DOT3_RGB_EXT:
3499 case GL_DOT3_RGBA_EXT:
3500 {
3501 /* Do not scale the result by 1 2 or 4 */
3502 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3503 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3504 for (i = 0; i < n; i++) {
3505 #if CHAN_TYPE == GL_FLOAT
3506 GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
3507 (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
3508 (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
3509 * 4.0F;
3510 dot = CLAMP(dot, 0.0F, CHAN_MAXF);
3511 #else
3512 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
3513 (GLint)arg1[i][RCOMP] - half) +
3514 S_PROD((GLint)arg0[i][GCOMP] - half,
3515 (GLint)arg1[i][GCOMP] - half) +
3516 S_PROD((GLint)arg0[i][BCOMP] - half,
3517 (GLint)arg1[i][BCOMP] - half)) >> 6;
3518 dot = CLAMP(dot, 0, CHAN_MAX);
3519 #endif
3520 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
3521 }
3522 }
3523 break;
3524 case GL_DOT3_RGB:
3525 case GL_DOT3_RGBA:
3526 {
3527 /* DO scale the result by 1 2 or 4 */
3528 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3529 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3530 for (i = 0; i < n; i++) {
3531 #if CHAN_TYPE == GL_FLOAT
3532 GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
3533 (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
3534 (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
3535 * 4.0F * RGBmult;
3536 dot = CLAMP(dot, 0.0, CHAN_MAXF);
3537 #else
3538 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
3539 (GLint)arg1[i][RCOMP] - half) +
3540 S_PROD((GLint)arg0[i][GCOMP] - half,
3541 (GLint)arg1[i][GCOMP] - half) +
3542 S_PROD((GLint)arg0[i][BCOMP] - half,
3543 (GLint)arg1[i][BCOMP] - half)) >> 6;
3544 dot <<= RGBshift;
3545 dot = CLAMP(dot, 0, CHAN_MAX);
3546 #endif
3547 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
3548 }
3549 }
3550 break;
3551 case GL_MODULATE_ADD_ATI:
3552 {
3553 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3554 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3555 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3556 #if CHAN_TYPE != GL_FLOAT
3557 const GLint shift = CHAN_BITS - RGBshift;
3558 #endif
3559 for (i = 0; i < n; i++) {
3560 #if CHAN_TYPE == GL_FLOAT
3561 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP]) * RGBmult;
3562 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP]) * RGBmult;
3563 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP]) * RGBmult;
3564 #else
3565 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3566 + ((GLuint) arg1[i][RCOMP] << CHAN_BITS)) >> shift;
3567 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3568 + ((GLuint) arg1[i][GCOMP] << CHAN_BITS)) >> shift;
3569 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3570 + ((GLuint) arg1[i][BCOMP] << CHAN_BITS)) >> shift;
3571 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
3572 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
3573 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
3574 #endif
3575 }
3576 }
3577 break;
3578 case GL_MODULATE_SIGNED_ADD_ATI:
3579 {
3580 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3581 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3582 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3583 #if CHAN_TYPE != GL_FLOAT
3584 const GLint shift = CHAN_BITS - RGBshift;
3585 #endif
3586 for (i = 0; i < n; i++) {
3587 #if CHAN_TYPE == GL_FLOAT
3588 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) + arg1[i][RCOMP] - 0.5) * RGBmult;
3589 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) + arg1[i][GCOMP] - 0.5) * RGBmult;
3590 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) + arg1[i][BCOMP] - 0.5) * RGBmult;
3591 #else
3592 GLint r = (S_PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3593 + (((GLint) arg1[i][RCOMP] - half) << CHAN_BITS))
3594 >> shift;
3595 GLint g = (S_PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3596 + (((GLint) arg1[i][GCOMP] - half) << CHAN_BITS))
3597 >> shift;
3598 GLint b = (S_PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3599 + (((GLint) arg1[i][BCOMP] - half) << CHAN_BITS))
3600 >> shift;
3601 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3602 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3603 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3604 #endif
3605 }
3606 }
3607 break;
3608 case GL_MODULATE_SUBTRACT_ATI:
3609 {
3610 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
3611 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
3612 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
3613 #if CHAN_TYPE != GL_FLOAT
3614 const GLint shift = CHAN_BITS - RGBshift;
3615 #endif
3616 for (i = 0; i < n; i++) {
3617 #if CHAN_TYPE == GL_FLOAT
3618 rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) - arg1[i][RCOMP]) * RGBmult;
3619 rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) - arg1[i][GCOMP]) * RGBmult;
3620 rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) - arg1[i][BCOMP]) * RGBmult;
3621 #else
3622 GLint r = (S_PROD(arg0[i][RCOMP], arg2[i][RCOMP])
3623 - ((GLint) arg1[i][RCOMP] << CHAN_BITS))
3624 >> shift;
3625 GLint g = (S_PROD(arg0[i][GCOMP], arg2[i][GCOMP])
3626 - ((GLint) arg1[i][GCOMP] << CHAN_BITS))
3627 >> shift;
3628 GLint b = (S_PROD(arg0[i][BCOMP], arg2[i][BCOMP])
3629 - ((GLint) arg1[i][BCOMP] << CHAN_BITS))
3630 >> shift;
3631 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
3632 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
3633 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
3634 #endif
3635 }
3636 }
3637 break;
3638 default:
3639 _mesa_problem(ctx, "invalid combine mode");
3640 }
3641
3642 switch (textureUnit->CombineModeA) {
3643 case GL_REPLACE:
3644 {
3645 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3646 if (Ashift) {
3647 for (i = 0; i < n; i++) {
3648 #if CHAN_TYPE == GL_FLOAT
3649 GLchan a = arg0[i][ACOMP] * Amult;
3650 #else
3651 GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
3652 #endif
3653 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3654 }
3655 }
3656 else {
3657 for (i = 0; i < n; i++) {
3658 rgba[i][ACOMP] = arg0[i][ACOMP];
3659 }
3660 }
3661 }
3662 break;
3663 case GL_MODULATE:
3664 {
3665 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3666 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3667 #if CHAN_TYPE != GL_FLOAT
3668 const GLint shift = CHAN_BITS - Ashift;
3669 #endif
3670 for (i = 0; i < n; i++) {
3671 #if CHAN_TYPE == GL_FLOAT
3672 rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * Amult;
3673 #else
3674 GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
3675 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3676 #endif
3677 }
3678 }
3679 break;
3680 case GL_ADD:
3681 {
3682 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3683 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3684 for (i = 0; i < n; i++) {
3685 #if CHAN_TYPE == GL_FLOAT
3686 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * Amult;
3687 #else
3688 GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
3689 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3690 #endif
3691 }
3692 }
3693 break;
3694 case GL_ADD_SIGNED:
3695 {
3696 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3697 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3698 for (i = 0; i < n; i++) {
3699 #if CHAN_TYPE == GL_FLOAT
3700 rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * Amult;
3701 #else
3702 GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] -half;
3703 a = (a < 0) ? 0 : a << Ashift;
3704 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3705 #endif
3706 }
3707 }
3708 break;
3709 case GL_INTERPOLATE:
3710 {
3711 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3712 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3713 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3714 #if CHAN_TYPE != GL_FLOAT
3715 const GLint shift = CHAN_BITS - Ashift;
3716 #endif
3717 for (i=0; i<n; i++) {
3718 #if CHAN_TYPE == GL_FLOAT
3719 rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
3720 arg1[i][ACOMP] * (CHAN_MAXF - arg2[i][ACOMP]))
3721 * Amult;
3722 #else
3723 GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3724 + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
3725 >> shift;
3726 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
3727 #endif
3728 }
3729 }
3730 break;
3731 case GL_SUBTRACT:
3732 {
3733 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3734 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3735 for (i = 0; i < n; i++) {
3736 #if CHAN_TYPE == GL_FLOAT
3737 rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * Amult;
3738 #else
3739 GLint a = ((GLint) arg0[i][ACOMP] - (GLint) arg1[i][ACOMP]) << Ashift;
3740 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3741 #endif
3742 }
3743 }
3744 break;
3745 case GL_MODULATE_ADD_ATI:
3746 {
3747 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3748 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3749 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3750 #if CHAN_TYPE != GL_FLOAT
3751 const GLint shift = CHAN_BITS - Ashift;
3752 #endif
3753 for (i = 0; i < n; i++) {
3754 #if CHAN_TYPE == GL_FLOAT
3755 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP]) * Amult;
3756 #else
3757 GLint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3758 + ((GLuint) arg1[i][ACOMP] << CHAN_BITS))
3759 >> shift;
3760 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3761 #endif
3762 }
3763 }
3764 break;
3765 case GL_MODULATE_SIGNED_ADD_ATI:
3766 {
3767 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3768 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3769 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3770 #if CHAN_TYPE != GL_FLOAT
3771 const GLint shift = CHAN_BITS - Ashift;
3772 #endif
3773 for (i = 0; i < n; i++) {
3774 #if CHAN_TYPE == GL_FLOAT
3775 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) + arg1[i][ACOMP] - 0.5F) * Amult;
3776 #else
3777 GLint a = (S_PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3778 + (((GLint) arg1[i][ACOMP] - half) << CHAN_BITS))
3779 >> shift;
3780 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3781 #endif
3782 }
3783 }
3784 break;
3785 case GL_MODULATE_SUBTRACT_ATI:
3786 {
3787 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
3788 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
3789 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
3790 #if CHAN_TYPE != GL_FLOAT
3791 const GLint shift = CHAN_BITS - Ashift;
3792 #endif
3793 for (i = 0; i < n; i++) {
3794 #if CHAN_TYPE == GL_FLOAT
3795 rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) - arg1[i][ACOMP]) * Amult;
3796 #else
3797 GLint a = (S_PROD(arg0[i][ACOMP], arg2[i][ACOMP])
3798 - ((GLint) arg1[i][ACOMP] << CHAN_BITS))
3799 >> shift;
3800 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
3801 #endif
3802 }
3803 }
3804 break;
3805 default:
3806 _mesa_problem(ctx, "invalid combine mode");
3807 }
3808
3809 /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
3810 * This is kind of a kludge. It would have been better if the spec
3811 * were written such that the GL_COMBINE_ALPHA value could be set to
3812 * GL_DOT3.
3813 */
3814 if (textureUnit->CombineModeRGB == GL_DOT3_RGBA_EXT ||
3815 textureUnit->CombineModeRGB == GL_DOT3_RGBA) {
3816 for (i = 0; i < n; i++) {
3817 rgba[i][ACOMP] = rgba[i][RCOMP];
3818 }
3819 }
3820 UNDEFARRAY(ccolor); /* mac 32k limitation */
3821 }
3822 #undef PROD
3823
3824
3825 /**
3826 * Implement NVIDIA's GL_NV_texture_env_combine4 extension when
3827 * texUnit->EnvMode == GL_COMBINE4_NV.
3828 */
3829 static INLINE void
3830 texture_combine4( const GLcontext *ctx, GLuint unit, GLuint n,
3831 CONST GLchan (*primary_rgba)[4],
3832 CONST GLchan *texelBuffer,
3833 GLchan (*rgba)[4] )
3834 {
3835 }
3836
3837
3838
3839 /**
3840 * Apply a conventional OpenGL texture env mode (REPLACE, ADD, BLEND,
3841 * MODULATE, or DECAL) to an array of fragments.
3842 * Input: textureUnit - pointer to texture unit to apply
3843 * format - base internal texture format
3844 * n - number of fragments
3845 * primary_rgba - primary colors (may alias rgba for single texture)
3846 * texels - array of texel colors
3847 * InOut: rgba - incoming fragment colors modified by texel colors
3848 * according to the texture environment mode.
3849 */
3850 static void
3851 texture_apply( const GLcontext *ctx,
3852 const struct gl_texture_unit *texUnit,
3853 GLuint n,
3854 CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
3855 GLchan rgba[][4] )
3856 {
3857 GLint baseLevel;
3858 GLuint i;
3859 GLint Rc, Gc, Bc, Ac;
3860 GLenum format;
3861
3862 ASSERT(texUnit);
3863 ASSERT(texUnit->_Current);
3864
3865 baseLevel = texUnit->_Current->BaseLevel;
3866 ASSERT(texUnit->_Current->Image[baseLevel]);
3867
3868 format = texUnit->_Current->Image[baseLevel]->Format;
3869
3870 if (format == GL_COLOR_INDEX || format == GL_YCBCR_MESA) {
3871 format = GL_RGBA; /* a bit of a hack */
3872 }
3873 else if (format == GL_DEPTH_COMPONENT) {
3874 format = texUnit->_Current->DepthMode;
3875 }
3876
3877 switch (texUnit->EnvMode) {
3878 case GL_REPLACE:
3879 switch (format) {
3880 case GL_ALPHA:
3881 for (i=0;i<n;i++) {
3882 /* Cv = Cf */
3883 /* Av = At */
3884 rgba[i][ACOMP] = texel[i][ACOMP];
3885 }
3886 break;
3887 case GL_LUMINANCE:
3888 for (i=0;i<n;i++) {
3889 /* Cv = Lt */
3890 GLchan Lt = texel[i][RCOMP];
3891 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
3892 /* Av = Af */
3893 }
3894 break;
3895 case GL_LUMINANCE_ALPHA:
3896 for (i=0;i<n;i++) {
3897 GLchan Lt = texel[i][RCOMP];
3898 /* Cv = Lt */
3899 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
3900 /* Av = At */
3901 rgba[i][ACOMP] = texel[i][ACOMP];
3902 }
3903 break;
3904 case GL_INTENSITY:
3905 for (i=0;i<n;i++) {
3906 /* Cv = It */
3907 GLchan It = texel[i][RCOMP];
3908 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
3909 /* Av = It */
3910 rgba[i][ACOMP] = It;
3911 }
3912 break;
3913 case GL_RGB:
3914 for (i=0;i<n;i++) {
3915 /* Cv = Ct */
3916 rgba[i][RCOMP] = texel[i][RCOMP];
3917 rgba[i][GCOMP] = texel[i][GCOMP];
3918 rgba[i][BCOMP] = texel[i][BCOMP];
3919 /* Av = Af */
3920 }
3921 break;
3922 case GL_RGBA:
3923 for (i=0;i<n;i++) {
3924 /* Cv = Ct */
3925 rgba[i][RCOMP] = texel[i][RCOMP];
3926 rgba[i][GCOMP] = texel[i][GCOMP];
3927 rgba[i][BCOMP] = texel[i][BCOMP];
3928 /* Av = At */
3929 rgba[i][ACOMP] = texel[i][ACOMP];
3930 }
3931 break;
3932 default:
3933 _mesa_problem(ctx, "Bad format (GL_REPLACE) in texture_apply");
3934 return;
3935 }
3936 break;
3937
3938 case GL_MODULATE:
3939 switch (format) {
3940 case GL_ALPHA:
3941 for (i=0;i<n;i++) {
3942 /* Cv = Cf */
3943 /* Av = AfAt */
3944 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3945 }
3946 break;
3947 case GL_LUMINANCE:
3948 for (i=0;i<n;i++) {
3949 /* Cv = LtCf */
3950 GLchan Lt = texel[i][RCOMP];
3951 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
3952 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
3953 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
3954 /* Av = Af */
3955 }
3956 break;
3957 case GL_LUMINANCE_ALPHA:
3958 for (i=0;i<n;i++) {
3959 /* Cv = CfLt */
3960 GLchan Lt = texel[i][RCOMP];
3961 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
3962 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
3963 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
3964 /* Av = AfAt */
3965 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3966 }
3967 break;
3968 case GL_INTENSITY:
3969 for (i=0;i<n;i++) {
3970 /* Cv = CfIt */
3971 GLchan It = texel[i][RCOMP];
3972 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
3973 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
3974 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
3975 /* Av = AfIt */
3976 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
3977 }
3978 break;
3979 case GL_RGB:
3980 for (i=0;i<n;i++) {
3981 /* Cv = CfCt */
3982 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
3983 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
3984 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
3985 /* Av = Af */
3986 }
3987 break;
3988 case GL_RGBA:
3989 for (i=0;i<n;i++) {
3990 /* Cv = CfCt */
3991 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
3992 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
3993 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
3994 /* Av = AfAt */
3995 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
3996 }
3997 break;
3998 default:
3999 _mesa_problem(ctx, "Bad format (GL_MODULATE) in texture_apply");
4000 return;
4001 }
4002 break;
4003
4004 case GL_DECAL:
4005 switch (format) {
4006 case GL_ALPHA:
4007 case GL_LUMINANCE:
4008 case GL_LUMINANCE_ALPHA:
4009 case GL_INTENSITY:
4010 /* undefined */
4011 break;
4012 case GL_RGB:
4013 for (i=0;i<n;i++) {
4014 /* Cv = Ct */
4015 rgba[i][RCOMP] = texel[i][RCOMP];
4016 rgba[i][GCOMP] = texel[i][GCOMP];
4017 rgba[i][BCOMP] = texel[i][BCOMP];
4018 /* Av = Af */
4019 }
4020 break;
4021 case GL_RGBA:
4022 for (i=0;i<n;i++) {
4023 /* Cv = Cf(1-At) + CtAt */
4024 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
4025 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
4026 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
4027 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
4028 /* Av = Af */
4029 }
4030 break;
4031 default:
4032 _mesa_problem(ctx, "Bad format (GL_DECAL) in texture_apply");
4033 return;
4034 }
4035 break;
4036
4037 case GL_BLEND:
4038 Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
4039 Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
4040 Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
4041 Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
4042 switch (format) {
4043 case GL_ALPHA:
4044 for (i=0;i<n;i++) {
4045 /* Cv = Cf */
4046 /* Av = AfAt */
4047 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
4048 }
4049 break;
4050 case GL_LUMINANCE:
4051 for (i=0;i<n;i++) {
4052 /* Cv = Cf(1-Lt) + CcLt */
4053 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
4054 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
4055 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
4056 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
4057 /* Av = Af */
4058 }
4059 break;
4060 case GL_LUMINANCE_ALPHA:
4061 for (i=0;i<n;i++) {
4062 /* Cv = Cf(1-Lt) + CcLt */
4063 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
4064 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
4065 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
4066 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
4067 /* Av = AfAt */
4068 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
4069 }
4070 break;
4071 case GL_INTENSITY:
4072 for (i=0;i<n;i++) {
4073 /* Cv = Cf(1-It) + CcLt */
4074 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
4075 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
4076 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
4077 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
4078 /* Av = Af(1-It) + Ac*It */
4079 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
4080 }
4081 break;
4082 case GL_RGB:
4083 for (i=0;i<n;i++) {
4084 /* Cv = Cf(1-Ct) + CcCt */
4085 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
4086 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
4087 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
4088 /* Av = Af */
4089 }
4090 break;
4091 case GL_RGBA:
4092 for (i=0;i<n;i++) {
4093 /* Cv = Cf(1-Ct) + CcCt */
4094 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
4095 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
4096 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
4097 /* Av = AfAt */
4098 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
4099 }
4100 break;
4101 default:
4102 _mesa_problem(ctx, "Bad format (GL_BLEND) in texture_apply");
4103 return;
4104 }
4105 break;
4106
4107 /* XXX don't clamp results if GLchan is float??? */
4108
4109 case GL_ADD: /* GL_EXT_texture_add_env */
4110 switch (format) {
4111 case GL_ALPHA:
4112 for (i=0;i<n;i++) {
4113 /* Rv = Rf */
4114 /* Gv = Gf */
4115 /* Bv = Bf */
4116 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
4117 }
4118 break;
4119 case GL_LUMINANCE:
4120 for (i=0;i<n;i++) {
4121 GLuint Lt = texel[i][RCOMP];
4122 GLuint r = rgba[i][RCOMP] + Lt;
4123 GLuint g = rgba[i][GCOMP] + Lt;
4124 GLuint b = rgba[i][BCOMP] + Lt;
4125 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
4126 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
4127 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
4128 /* Av = Af */
4129 }
4130 break;
4131 case GL_LUMINANCE_ALPHA:
4132 for (i=0;i<n;i++) {
4133 GLuint Lt = texel[i][RCOMP];
4134 GLuint r = rgba[i][RCOMP] + Lt;
4135 GLuint g = rgba[i][GCOMP] + Lt;
4136 GLuint b = rgba[i][BCOMP] + Lt;
4137 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
4138 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
4139 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
4140 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
4141 }
4142 break;
4143 case GL_INTENSITY:
4144 for (i=0;i<n;i++) {
4145 GLchan It = texel[i][RCOMP];
4146 GLuint r = rgba[i][RCOMP] + It;
4147 GLuint g = rgba[i][GCOMP] + It;
4148 GLuint b = rgba[i][BCOMP] + It;
4149 GLuint a = rgba[i][ACOMP] + It;
4150 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
4151 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
4152 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
4153 rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
4154 }
4155 break;
4156 case GL_RGB:
4157 for (i=0;i<n;i++) {
4158 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
4159 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
4160 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
4161 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
4162 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
4163 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
4164 /* Av = Af */
4165 }
4166 break;
4167 case GL_RGBA:
4168 for (i=0;i<n;i++) {
4169 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
4170 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
4171 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
4172 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
4173 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
4174 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
4175 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
4176 }
4177 break;
4178 default:
4179 _mesa_problem(ctx, "Bad format (GL_ADD) in texture_apply");
4180 return;
4181 }
4182 break;
4183
4184 default:
4185 _mesa_problem(ctx, "Bad env mode in texture_apply");
4186 return;
4187 }
4188 }
4189
4190
4191
4192 /**
4193 * Apply texture mapping to a span of fragments.
4194 */
4195 void
4196 _swrast_texture_span( GLcontext *ctx, struct sw_span *span )
4197 {
4198 SWcontext *swrast = SWRAST_CONTEXT(ctx);
4199 GLchan primary_rgba[MAX_WIDTH][4];
4200 GLuint unit;
4201
4202 ASSERT(span->end < MAX_WIDTH);
4203 ASSERT(span->arrayMask & SPAN_TEXTURE);
4204
4205 /*
4206 * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
4207 */
4208 if (swrast->_AnyTextureCombine)
4209 MEMCPY(primary_rgba, span->array->rgba, 4 * span->end * sizeof(GLchan));
4210
4211 /*
4212 * Must do all texture sampling before combining in order to
4213 * accomodate GL_ARB_texture_env_crossbar.
4214 */
4215 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
4216 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
4217 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
4218 const struct gl_texture_object *curObj = texUnit->_Current;
4219 GLfloat *lambda = span->array->lambda[unit];
4220 GLchan (*texels)[4] = (GLchan (*)[4])
4221 (swrast->TexelBuffer + unit * (span->end * 4 * sizeof(GLchan)));
4222
4223 /* adjust texture lod (lambda) */
4224 if (span->arrayMask & SPAN_LAMBDA) {
4225 if (texUnit->LodBias + curObj->LodBias != 0.0F) {
4226 /* apply LOD bias, but don't clamp yet */
4227 const GLfloat bias = CLAMP(texUnit->LodBias + curObj->LodBias,
4228 -ctx->Const.MaxTextureLodBias,
4229 ctx->Const.MaxTextureLodBias);
4230 GLuint i;
4231 for (i = 0; i < span->end; i++) {
4232 lambda[i] += bias;
4233 }
4234 }
4235
4236 if (curObj->MinLod != -1000.0 || curObj->MaxLod != 1000.0) {
4237 /* apply LOD clamping to lambda */
4238 const GLfloat min = curObj->MinLod;
4239 const GLfloat max = curObj->MaxLod;
4240 GLuint i;
4241 for (i = 0; i < span->end; i++) {
4242 GLfloat l = lambda[i];
4243 lambda[i] = CLAMP(l, min, max);
4244 }
4245 }
4246 }
4247
4248 /* Sample the texture (span->end fragments) */
4249 swrast->TextureSample[unit]( ctx, unit, texUnit->_Current, span->end,
4250 (const GLfloat (*)[4]) span->array->texcoords[unit],
4251 lambda, texels );
4252
4253 /* GL_SGI_texture_color_table */
4254 if (texUnit->ColorTableEnabled) {
4255 _swrast_texture_table_lookup(&texUnit->ColorTable, span->end, texels);
4256 }
4257 }
4258 }
4259
4260 /*
4261 * OK, now apply the texture (aka texture combine/blend).
4262 * We modify the span->color.rgba values.
4263 */
4264 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
4265 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
4266 const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
4267 if (texUnit->EnvMode == GL_COMBINE) {
4268 /* GL_ARB/EXT_texture_env_combine */
4269 texture_combine( ctx, unit, span->end,
4270 (CONST GLchan (*)[4]) primary_rgba,
4271 swrast->TexelBuffer,
4272 span->array->rgba );
4273 }
4274 else if (texUnit->EnvMode == GL_COMBINE4_NV) {
4275 /* GL_NV_texture_env_combine4 */
4276 texture_combine4( ctx, unit, span->end,
4277 (CONST GLchan (*)[4]) primary_rgba,
4278 swrast->TexelBuffer,
4279 span->array->rgba );
4280 }
4281 else {
4282 /* conventional texture blend */
4283 const GLchan (*texels)[4] = (const GLchan (*)[4])
4284 (swrast->TexelBuffer + unit *
4285 (span->end * 4 * sizeof(GLchan)));
4286 texture_apply( ctx, texUnit, span->end,
4287 (CONST GLchan (*)[4]) primary_rgba, texels,
4288 span->array->rgba );
4289 }
4290 }
4291 }
4292 }