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