Fix typo
[mesa.git] / src / mesa / swrast / s_texture.c
1 /* $Id: s_texture.c,v 1.14 2001/03/03 20:33:30 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #include "glheader.h"
29 #include "context.h"
30 #include "colormac.h"
31 #include "macros.h"
32 #include "mmath.h"
33 #include "mem.h"
34 #include "teximage.h"
35
36 #include "s_context.h"
37 #include "s_pb.h"
38 #include "s_texture.h"
39
40
41
42 /*
43 * These values are used in the fixed-point arithmetic used
44 * for linear filtering.
45 */
46 #define WEIGHT_SCALE 65536.0F
47 #define WEIGHT_SHIFT 16
48
49
50 /*
51 * Used to compute texel locations for linear sampling.
52 * Input:
53 * wrapMode = GL_REPEAT, GL_CLAMP or GL_CLAMP_TO_EDGE
54 * S = texcoord in [0,1]
55 * SIZE = width (or height or depth) of texture
56 * Output:
57 * U = texcoord in [0, width]
58 * I0, I1 = two nearest texel indexes
59 */
60 #define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
61 { \
62 if (wrapMode == GL_REPEAT) { \
63 U = S * SIZE - 0.5F; \
64 I0 = IFLOOR(U) & (SIZE - 1); \
65 I1 = (I0 + 1) & (SIZE - 1); \
66 } \
67 else { \
68 U = S * SIZE; \
69 if (U < 0.0F) \
70 U = 0.0F; \
71 else if (U >= SIZE) \
72 U = SIZE; \
73 U -= 0.5F; \
74 I0 = IFLOOR(U); \
75 I1 = I0 + 1; \
76 if (wrapMode == GL_CLAMP_TO_EDGE) { \
77 if (I0 < 0) \
78 I0 = 0; \
79 if (I1 >= SIZE) \
80 I1 = SIZE - 1; \
81 } \
82 } \
83 }
84
85
86 /*
87 * Used to compute texel location for nearest sampling.
88 */
89 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
90 { \
91 if (wrapMode == GL_REPEAT) { \
92 /* s limited to [0,1) */ \
93 /* i limited to [0,width-1] */ \
94 I = (GLint) (S * SIZE); \
95 if (S < 0.0F) \
96 I -= 1; \
97 I &= (SIZE - 1); \
98 } \
99 else if (wrapMode == GL_CLAMP_TO_EDGE) { \
100 const GLfloat min = 1.0F / (2.0F * SIZE); \
101 const GLfloat max = 1.0F - min; \
102 if (S < min) \
103 I = 0; \
104 else if (S > max) \
105 I = SIZE - 1; \
106 else \
107 I = (GLint) (S * SIZE); \
108 } \
109 else { \
110 ASSERT(wrapMode == GL_CLAMP); \
111 /* s limited to [0,1] */ \
112 /* i limited to [0,width-1] */ \
113 if (S <= 0.0F) \
114 I = 0; \
115 else if (S >= 1.0F) \
116 I = SIZE - 1; \
117 else \
118 I = (GLint) (S * SIZE); \
119 } \
120 }
121
122
123 /*
124 * Compute linear mipmap levels for given lambda.
125 */
126 #define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level) \
127 { \
128 if (lambda < 0.0F) \
129 lambda = 0.0F; \
130 else if (lambda > tObj->_MaxLambda) \
131 lambda = tObj->_MaxLambda; \
132 level = (GLint) (tObj->BaseLevel + lambda); \
133 }
134
135
136 /*
137 * Compute nearest mipmap level for given lambda.
138 */
139 #define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \
140 { \
141 if (lambda <= 0.5F) \
142 lambda = 0.0F; \
143 else if (lambda > tObj->_MaxLambda + 0.4999F) \
144 lambda = tObj->_MaxLambda + 0.4999F; \
145 level = (GLint) (tObj->BaseLevel + lambda + 0.5F); \
146 if (level > tObj->_MaxLevel) \
147 level = tObj->_MaxLevel; \
148 }
149
150
151
152
153 /*
154 * Bitflags for texture border color sampling.
155 */
156 #define I0BIT 1
157 #define I1BIT 2
158 #define J0BIT 4
159 #define J1BIT 8
160 #define K0BIT 16
161 #define K1BIT 32
162
163
164
165 /*
166 * Get texture palette entry.
167 */
168 static void
169 palette_sample(const GLcontext *ctx,
170 const struct gl_texture_object *tObj,
171 GLint index, GLchan rgba[4] )
172 {
173 const GLchan *palette;
174 GLenum format;
175
176 if (ctx->Texture.SharedPalette) {
177 ASSERT(!ctx->Texture.Palette.FloatTable);
178 palette = (const GLchan *) ctx->Texture.Palette.Table;
179 format = ctx->Texture.Palette.Format;
180 }
181 else {
182 ASSERT(!tObj->Palette.FloatTable);
183 palette = (const GLchan *) tObj->Palette.Table;
184 format = tObj->Palette.Format;
185 }
186
187 switch (format) {
188 case GL_ALPHA:
189 rgba[ACOMP] = palette[index];
190 return;
191 case GL_LUMINANCE:
192 case GL_INTENSITY:
193 rgba[RCOMP] = palette[index];
194 return;
195 case GL_LUMINANCE_ALPHA:
196 rgba[RCOMP] = palette[(index << 1) + 0];
197 rgba[ACOMP] = palette[(index << 1) + 1];
198 return;
199 case GL_RGB:
200 rgba[RCOMP] = palette[index * 3 + 0];
201 rgba[GCOMP] = palette[index * 3 + 1];
202 rgba[BCOMP] = palette[index * 3 + 2];
203 return;
204 case GL_RGBA:
205 rgba[RCOMP] = palette[(index << 2) + 0];
206 rgba[GCOMP] = palette[(index << 2) + 1];
207 rgba[BCOMP] = palette[(index << 2) + 2];
208 rgba[ACOMP] = palette[(index << 2) + 3];
209 return;
210 default:
211 _mesa_problem(ctx, "Bad palette format in palette_sample");
212 }
213 }
214
215
216
217 /**********************************************************************/
218 /* 1-D Texture Sampling Functions */
219 /**********************************************************************/
220
221 /*
222 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
223 */
224 static void
225 sample_1d_nearest(GLcontext *ctx,
226 const struct gl_texture_object *tObj,
227 const struct gl_texture_image *img,
228 GLfloat s, GLchan rgba[4])
229 {
230 const GLint width = img->Width2; /* without border, power of two */
231 GLint i;
232
233 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
234
235 /* skip over the border, if any */
236 i += img->Border;
237
238 (*img->FetchTexel)(img, i, 0, 0, (GLvoid *) rgba);
239 if (img->Format == GL_COLOR_INDEX) {
240 palette_sample(ctx, tObj, rgba[0], rgba);
241 }
242 }
243
244
245
246 /*
247 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
248 */
249 static void
250 sample_1d_linear(GLcontext *ctx,
251 const struct gl_texture_object *tObj,
252 const struct gl_texture_image *img,
253 GLfloat s, GLchan rgba[4])
254 {
255 const GLint width = img->Width2;
256 GLint i0, i1;
257 GLfloat u;
258 GLuint useBorderColor;
259
260 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
261
262 useBorderColor = 0;
263 if (img->Border) {
264 i0 += img->Border;
265 i1 += img->Border;
266 }
267 else {
268 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
269 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
270 }
271
272 {
273 const GLfloat a = FRAC(u);
274 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
275 const GLint w0 = (GLint) ((1.0F-a) * WEIGHT_SCALE + 0.5F);
276 const GLint w1 = (GLint) ( a * WEIGHT_SCALE + 0.5F);
277
278 GLchan t0[4], t1[4]; /* texels */
279
280 if (useBorderColor & I0BIT) {
281 COPY_CHAN4(t0, tObj->BorderColor);
282 }
283 else {
284 (*img->FetchTexel)(img, i0, 0, 0, (GLvoid *) t0);
285 if (img->Format == GL_COLOR_INDEX) {
286 palette_sample(ctx, tObj, t0[0], t0);
287 }
288 }
289 if (useBorderColor & I1BIT) {
290 COPY_CHAN4(t1, tObj->BorderColor);
291 }
292 else {
293 (*img->FetchTexel)(img, i1, 0, 0, (GLvoid *) t1);
294 if (img->Format == GL_COLOR_INDEX) {
295 palette_sample(ctx, tObj, t1[0], t1);
296 }
297 }
298
299 rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT);
300 rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT);
301 rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT);
302 rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT);
303 }
304 }
305
306
307 static void
308 sample_1d_nearest_mipmap_nearest(GLcontext *ctx,
309 const struct gl_texture_object *tObj,
310 GLfloat s, GLfloat lambda,
311 GLchan rgba[4])
312 {
313 GLint level;
314 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
315 sample_1d_nearest(ctx, tObj, tObj->Image[level], s, rgba);
316 }
317
318
319 static void
320 sample_1d_linear_mipmap_nearest(GLcontext *ctx,
321 const struct gl_texture_object *tObj,
322 GLfloat s, GLfloat lambda,
323 GLchan rgba[4])
324 {
325 GLint level;
326 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
327 sample_1d_linear(ctx, tObj, tObj->Image[level], s, rgba);
328 }
329
330
331
332 static void
333 sample_1d_nearest_mipmap_linear(GLcontext *ctx,
334 const struct gl_texture_object *tObj,
335 GLfloat s, GLfloat lambda,
336 GLchan rgba[4])
337 {
338 GLint level;
339
340 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
341
342 if (level >= tObj->_MaxLevel) {
343 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel], s, rgba);
344 }
345 else {
346 GLchan t0[4], t1[4];
347 const GLfloat f = FRAC(lambda);
348 sample_1d_nearest(ctx, tObj, tObj->Image[level ], s, t0);
349 sample_1d_nearest(ctx, tObj, tObj->Image[level+1], s, t1);
350 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
351 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
352 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
353 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
354 }
355 }
356
357
358
359 static void
360 sample_1d_linear_mipmap_linear(GLcontext *ctx,
361 const struct gl_texture_object *tObj,
362 GLfloat s, GLfloat lambda,
363 GLchan rgba[4])
364 {
365 GLint level;
366
367 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
368
369 if (level >= tObj->_MaxLevel) {
370 sample_1d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], s, rgba);
371 }
372 else {
373 GLchan t0[4], t1[4];
374 const GLfloat f = FRAC(lambda);
375 sample_1d_linear(ctx, tObj, tObj->Image[level ], s, t0);
376 sample_1d_linear(ctx, tObj, tObj->Image[level+1], s, t1);
377 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
378 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
379 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
380 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
381 }
382 }
383
384
385
386 static void
387 sample_nearest_1d( GLcontext *ctx, GLuint texUnit,
388 const struct gl_texture_object *tObj, GLuint n,
389 const GLfloat s[], const GLfloat t[],
390 const GLfloat u[], const GLfloat lambda[],
391 GLchan rgba[][4] )
392 {
393 GLuint i;
394 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
395 (void) t;
396 (void) u;
397 (void) lambda;
398 for (i=0;i<n;i++) {
399 sample_1d_nearest(ctx, tObj, image, s[i], rgba[i]);
400 }
401 }
402
403
404
405 static void
406 sample_linear_1d( GLcontext *ctx, GLuint texUnit,
407 const struct gl_texture_object *tObj, GLuint n,
408 const GLfloat s[], const GLfloat t[],
409 const GLfloat u[], const GLfloat lambda[],
410 GLchan rgba[][4] )
411 {
412 GLuint i;
413 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
414 (void) t;
415 (void) u;
416 (void) lambda;
417 for (i=0;i<n;i++) {
418 sample_1d_linear(ctx, tObj, image, s[i], rgba[i]);
419 }
420 }
421
422
423 /*
424 * Given an (s) texture coordinate and lambda (level of detail) value,
425 * return a texture sample.
426 *
427 */
428 static void
429 sample_lambda_1d( GLcontext *ctx, GLuint texUnit,
430 const struct gl_texture_object *tObj, GLuint n,
431 const GLfloat s[], const GLfloat t[],
432 const GLfloat u[], const GLfloat lambda[],
433 GLchan rgba[][4] )
434 {
435 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
436 GLuint i;
437
438 (void) t;
439 (void) u;
440
441 for (i=0;i<n;i++) {
442 if (lambda[i] > MinMagThresh) {
443 /* minification */
444 switch (tObj->MinFilter) {
445 case GL_NEAREST:
446 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
447 s[i], rgba[i]);
448 break;
449 case GL_LINEAR:
450 sample_1d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
451 s[i], rgba[i]);
452 break;
453 case GL_NEAREST_MIPMAP_NEAREST:
454 sample_1d_nearest_mipmap_nearest(ctx, tObj, lambda[i], s[i],
455 rgba[i]);
456 break;
457 case GL_LINEAR_MIPMAP_NEAREST:
458 sample_1d_linear_mipmap_nearest(ctx, tObj, s[i], lambda[i],
459 rgba[i]);
460 break;
461 case GL_NEAREST_MIPMAP_LINEAR:
462 sample_1d_nearest_mipmap_linear(ctx, tObj, s[i], lambda[i],
463 rgba[i]);
464 break;
465 case GL_LINEAR_MIPMAP_LINEAR:
466 sample_1d_linear_mipmap_linear(ctx, tObj, s[i], lambda[i],
467 rgba[i]);
468 break;
469 default:
470 _mesa_problem(NULL, "Bad min filter in sample_1d_texture");
471 return;
472 }
473 }
474 else {
475 /* magnification */
476 switch (tObj->MagFilter) {
477 case GL_NEAREST:
478 sample_1d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
479 s[i], rgba[i]);
480 break;
481 case GL_LINEAR:
482 sample_1d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
483 s[i], rgba[i]);
484 break;
485 default:
486 _mesa_problem(NULL, "Bad mag filter in sample_1d_texture");
487 return;
488 }
489 }
490 }
491 }
492
493
494
495
496 /**********************************************************************/
497 /* 2-D Texture Sampling Functions */
498 /**********************************************************************/
499
500
501 /*
502 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
503 */
504 static void
505 sample_2d_nearest(GLcontext *ctx,
506 const struct gl_texture_object *tObj,
507 const struct gl_texture_image *img,
508 GLfloat s, GLfloat t,
509 GLchan rgba[])
510 {
511 const GLint width = img->Width2; /* without border, power of two */
512 const GLint height = img->Height2; /* without border, power of two */
513 GLint i, j;
514
515 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
516 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
517
518 /* skip over the border, if any */
519 i += img->Border;
520 j += img->Border;
521
522 (*img->FetchTexel)(img, i, j, 0, (GLvoid *) rgba);
523 if (img->Format == GL_COLOR_INDEX) {
524 palette_sample(ctx, tObj, rgba[0], rgba);
525 }
526 }
527
528
529
530 /*
531 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
532 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
533 */
534 static void
535 sample_2d_linear(GLcontext *ctx,
536 const struct gl_texture_object *tObj,
537 const struct gl_texture_image *img,
538 GLfloat s, GLfloat t,
539 GLchan rgba[])
540 {
541 const GLint width = img->Width2;
542 const GLint height = img->Height2;
543 GLint i0, j0, i1, j1;
544 GLuint useBorderColor;
545 GLfloat u, v;
546
547 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
548 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
549
550 useBorderColor = 0;
551 if (img->Border) {
552 i0 += img->Border;
553 i1 += img->Border;
554 j0 += img->Border;
555 j1 += img->Border;
556 }
557 else {
558 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
559 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
560 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
561 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
562 }
563
564 {
565 const GLfloat a = FRAC(u);
566 const GLfloat b = FRAC(v);
567 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
568 const GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * WEIGHT_SCALE + 0.5F);
569 const GLint w10 = (GLint) ( a *(1.0F-b) * WEIGHT_SCALE + 0.5F);
570 const GLint w01 = (GLint) ((1.0F-a)* b * WEIGHT_SCALE + 0.5F);
571 const GLint w11 = (GLint) ( a * b * WEIGHT_SCALE + 0.5F);
572 GLchan t00[4];
573 GLchan t10[4];
574 GLchan t01[4];
575 GLchan t11[4];
576
577 if (useBorderColor & (I0BIT | J0BIT)) {
578 COPY_CHAN4(t00, tObj->BorderColor);
579 }
580 else {
581 (*img->FetchTexel)(img, i0, j0, 0, (GLvoid *) t00);
582 if (img->Format == GL_COLOR_INDEX) {
583 palette_sample(ctx, tObj, t00[0], t00);
584 }
585 }
586 if (useBorderColor & (I1BIT | J0BIT)) {
587 COPY_CHAN4(t10, tObj->BorderColor);
588 }
589 else {
590 (*img->FetchTexel)(img, i1, j0, 0, (GLvoid *) t10);
591 if (img->Format == GL_COLOR_INDEX) {
592 palette_sample(ctx, tObj, t10[0], t10);
593 }
594 }
595 if (useBorderColor & (I0BIT | J1BIT)) {
596 COPY_CHAN4(t01, tObj->BorderColor);
597 }
598 else {
599 (*img->FetchTexel)(img, i0, j1, 0, (GLvoid *) t01);
600 if (img->Format == GL_COLOR_INDEX) {
601 palette_sample(ctx, tObj, t01[0], t01);
602 }
603 }
604 if (useBorderColor & (I1BIT | J1BIT)) {
605 COPY_CHAN4(t11, tObj->BorderColor);
606 }
607 else {
608 (*img->FetchTexel)(img, i1, j1, 0, (GLvoid *) t11);
609 if (img->Format == GL_COLOR_INDEX) {
610 palette_sample(ctx, tObj, t11[0], t11);
611 }
612 }
613
614 rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT);
615 rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT);
616 rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT);
617 rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT);
618 }
619
620 }
621
622
623
624 static void
625 sample_2d_nearest_mipmap_nearest(GLcontext *ctx,
626 const struct gl_texture_object *tObj,
627 GLfloat s, GLfloat t, GLfloat lambda,
628 GLchan rgba[4])
629 {
630 GLint level;
631 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
632 sample_2d_nearest(ctx, tObj, tObj->Image[level], s, t, rgba);
633 }
634
635
636
637 static void
638 sample_2d_linear_mipmap_nearest(GLcontext *ctx,
639 const struct gl_texture_object *tObj,
640 GLfloat s, GLfloat t, GLfloat lambda,
641 GLchan rgba[4])
642 {
643 GLint level;
644 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
645 sample_2d_linear(ctx, tObj, tObj->Image[level], s, t, rgba);
646 }
647
648
649
650 static void
651 sample_2d_nearest_mipmap_linear(GLcontext *ctx,
652 const struct gl_texture_object *tObj,
653 GLfloat s, GLfloat t, GLfloat lambda,
654 GLchan rgba[4])
655 {
656 GLint level;
657
658 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
659
660 if (level >= tObj->_MaxLevel) {
661 sample_2d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel], s, t, rgba);
662 }
663 else {
664 GLchan t0[4], t1[4]; /* texels */
665 const GLfloat f = FRAC(lambda);
666 sample_2d_nearest(ctx, tObj, tObj->Image[level ], s, t, t0);
667 sample_2d_nearest(ctx, tObj, tObj->Image[level+1], s, t, t1);
668 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
669 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
670 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
671 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
672 }
673 }
674
675
676
677 static void
678 sample_2d_linear_mipmap_linear(GLcontext *ctx,
679 const struct gl_texture_object *tObj,
680 GLfloat s, GLfloat t, GLfloat lambda,
681 GLchan rgba[4])
682 {
683 GLint level;
684
685 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
686
687 if (level >= tObj->_MaxLevel) {
688 sample_2d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], s, t, rgba);
689 }
690 else {
691 GLchan t0[4], t1[4]; /* texels */
692 const GLfloat f = FRAC(lambda);
693 sample_2d_linear(ctx, tObj, tObj->Image[level ], s, t, t0);
694 sample_2d_linear(ctx, tObj, tObj->Image[level+1], s, t, t1);
695 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
696 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
697 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
698 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
699 }
700 }
701
702
703
704 static void
705 sample_nearest_2d( GLcontext *ctx, GLuint texUnit,
706 const struct gl_texture_object *tObj, GLuint n,
707 const GLfloat s[], const GLfloat t[],
708 const GLfloat u[], const GLfloat lambda[],
709 GLchan rgba[][4] )
710 {
711 GLuint i;
712 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
713 (void) u;
714 (void) lambda;
715 for (i=0;i<n;i++) {
716 sample_2d_nearest(ctx, tObj, image, s[i], t[i], rgba[i]);
717 }
718 }
719
720
721
722 static void
723 sample_linear_2d( GLcontext *ctx, GLuint texUnit,
724 const struct gl_texture_object *tObj, GLuint n,
725 const GLfloat s[], const GLfloat t[],
726 const GLfloat u[], const GLfloat lambda[],
727 GLchan rgba[][4] )
728 {
729 GLuint i;
730 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
731 (void) u;
732 (void) lambda;
733 for (i=0;i<n;i++) {
734 sample_2d_linear(ctx, tObj, image, s[i], t[i], rgba[i]);
735 }
736 }
737
738
739 /*
740 * Given an array of (s,t) texture coordinate and lambda (level of detail)
741 * values, return an array of texture sample.
742 */
743 static void
744 sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
745 const struct gl_texture_object *tObj,
746 GLuint n,
747 const GLfloat s[], const GLfloat t[],
748 const GLfloat u[], const GLfloat lambda[],
749 GLchan rgba[][4] )
750 {
751 const GLfloat minMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
752 GLuint i;
753 (void) u;
754
755 /* check if lambda is monotonous-array */
756 if (lambda[0] <= minMagThresh && lambda[n-1] <= minMagThresh) {
757 /* magnification */
758 switch (tObj->MagFilter) {
759 case GL_NEAREST:
760 for (i = 0; i < n; i++)
761 sample_2d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
762 s[i], t[i], rgba[i] );
763 break;
764 case GL_LINEAR:
765 for (i = 0; i < n; i++)
766 sample_2d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
767 s[i], t[i], rgba[i] );
768 break;
769 default:
770 _mesa_problem(NULL, "Bad mag filter in sample_2d_texture");
771 }
772 }
773 else {
774 for (i = 0; i < n; i++) {
775 if (lambda[i] > minMagThresh) {
776 /* minification */
777 switch (tObj->MinFilter) {
778 case GL_NEAREST:
779 sample_2d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
780 s[i], t[i], rgba[i]);
781 break;
782 case GL_LINEAR:
783 sample_2d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
784 s[i], t[i], rgba[i]);
785 break;
786 case GL_NEAREST_MIPMAP_NEAREST:
787 sample_2d_nearest_mipmap_nearest(ctx, tObj, s[i], t[i],
788 lambda[i], rgba[i]);
789 break;
790 case GL_LINEAR_MIPMAP_NEAREST:
791 sample_2d_linear_mipmap_nearest(ctx,tObj, s[i], t[i],
792 lambda[i], rgba[i]);
793 break;
794 case GL_NEAREST_MIPMAP_LINEAR:
795 sample_2d_nearest_mipmap_linear(ctx,tObj, s[i], t[i],
796 lambda[i], rgba[i]);
797 break;
798 case GL_LINEAR_MIPMAP_LINEAR:
799 sample_2d_linear_mipmap_linear(ctx,tObj, s[i], t[i],
800 lambda[i], rgba[i] );
801 break;
802 default:
803 _mesa_problem(NULL, "Bad min filter in sample_2d_texture");
804 return;
805 }
806 }
807 else {
808 /* magnification */
809 switch (tObj->MagFilter) {
810 case GL_NEAREST:
811 sample_2d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
812 s[i], t[i], rgba[i]);
813 break;
814 case GL_LINEAR:
815 sample_2d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
816 s[i], t[i], rgba[i] );
817 break;
818 default:
819 _mesa_problem(NULL, "Bad mag filter in sample_2d_texture");
820 }
821 }
822 }
823 }
824 }
825
826
827 /*
828 * Optimized 2-D texture sampling:
829 * S and T wrap mode == GL_REPEAT
830 * GL_NEAREST min/mag filter
831 * No border
832 * Format = GL_RGB
833 */
834 static void
835 opt_sample_rgb_2d( GLcontext *ctx, GLuint texUnit,
836 const struct gl_texture_object *tObj,
837 GLuint n, const GLfloat s[], const GLfloat t[],
838 const GLfloat u[], const GLfloat lambda[],
839 GLchan rgba[][4] )
840 {
841 const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
842 const GLfloat width = (GLfloat) img->Width;
843 const GLfloat height = (GLfloat) img->Height;
844 const GLint colMask = img->Width - 1;
845 const GLint rowMask = img->Height - 1;
846 const GLint shift = img->WidthLog2;
847 GLuint k;
848 (void) u;
849 (void) lambda;
850 ASSERT(tObj->WrapS==GL_REPEAT);
851 ASSERT(tObj->WrapT==GL_REPEAT);
852 ASSERT(tObj->MinFilter==GL_NEAREST);
853 ASSERT(tObj->MagFilter==GL_NEAREST);
854 ASSERT(img->Border==0);
855 ASSERT(img->Format==GL_RGB);
856
857 /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
858 for (k=0;k<n;k++) {
859 GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
860 GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
861 GLint pos = (j << shift) | i;
862 GLchan *texel = ((GLchan *) img->Data) + pos + pos + pos; /* pos*3 */
863 rgba[k][RCOMP] = texel[0];
864 rgba[k][GCOMP] = texel[1];
865 rgba[k][BCOMP] = texel[2];
866 }
867 }
868
869
870 /*
871 * Optimized 2-D texture sampling:
872 * S and T wrap mode == GL_REPEAT
873 * GL_NEAREST min/mag filter
874 * No border
875 * Format = GL_RGBA
876 */
877 static void
878 opt_sample_rgba_2d( GLcontext *ctx, GLuint texUnit,
879 const struct gl_texture_object *tObj,
880 GLuint n, const GLfloat s[], const GLfloat t[],
881 const GLfloat u[], const GLfloat lambda[],
882 GLchan rgba[][4] )
883 {
884 const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel];
885 const GLfloat width = (GLfloat) img->Width;
886 const GLfloat height = (GLfloat) img->Height;
887 const GLint colMask = img->Width - 1;
888 const GLint rowMask = img->Height - 1;
889 const GLint shift = img->WidthLog2;
890 GLuint k;
891 (void) u;
892 (void) lambda;
893 ASSERT(tObj->WrapS==GL_REPEAT);
894 ASSERT(tObj->WrapT==GL_REPEAT);
895 ASSERT(tObj->MinFilter==GL_NEAREST);
896 ASSERT(tObj->MagFilter==GL_NEAREST);
897 ASSERT(img->Border==0);
898 ASSERT(img->Format==GL_RGBA);
899
900 /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */
901 for (k=0;k<n;k++) {
902 GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask;
903 GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask;
904 GLint pos = (j << shift) | i;
905 GLchan *texel = ((GLchan *) img->Data) + (pos << 2); /* pos*4 */
906 rgba[k][RCOMP] = texel[0];
907 rgba[k][GCOMP] = texel[1];
908 rgba[k][BCOMP] = texel[2];
909 rgba[k][ACOMP] = texel[3];
910 }
911 }
912
913
914
915 /**********************************************************************/
916 /* 3-D Texture Sampling Functions */
917 /**********************************************************************/
918
919 /*
920 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
921 */
922 static void
923 sample_3d_nearest(GLcontext *ctx,
924 const struct gl_texture_object *tObj,
925 const struct gl_texture_image *img,
926 GLfloat s, GLfloat t, GLfloat r,
927 GLchan rgba[4])
928 {
929 const GLint width = img->Width2; /* without border, power of two */
930 const GLint height = img->Height2; /* without border, power of two */
931 const GLint depth = img->Depth2; /* without border, power of two */
932 GLint i, j, k;
933
934 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i);
935 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j);
936 COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, r, depth, k);
937
938 (*img->FetchTexel)(img, i, j, k, (GLvoid *) rgba);
939 if (img->Format == GL_COLOR_INDEX) {
940 palette_sample(ctx, tObj, rgba[0], rgba);
941 }
942 }
943
944
945
946 /*
947 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
948 */
949 static void
950 sample_3d_linear(GLcontext *ctx,
951 const struct gl_texture_object *tObj,
952 const struct gl_texture_image *img,
953 GLfloat s, GLfloat t, GLfloat r,
954 GLchan rgba[4])
955 {
956 const GLint width = img->Width2;
957 const GLint height = img->Height2;
958 const GLint depth = img->Depth2;
959 GLint i0, j0, k0, i1, j1, k1;
960 GLuint useBorderColor;
961 GLfloat u, v, w;
962
963 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1);
964 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1);
965 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, r, w, depth, k0, k1);
966
967 useBorderColor = 0;
968 if (img->Border) {
969 i0 += img->Border;
970 i1 += img->Border;
971 j0 += img->Border;
972 j1 += img->Border;
973 k0 += img->Border;
974 k1 += img->Border;
975 }
976 else {
977 /* check if sampling texture border color */
978 if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
979 if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
980 if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
981 if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
982 if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
983 if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
984 }
985
986 {
987 const GLfloat a = FRAC(u);
988 const GLfloat b = FRAC(v);
989 const GLfloat c = FRAC(w);
990 /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */
991 GLint w000 = (GLint) ((1.0F-a)*(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
992 GLint w100 = (GLint) ( a *(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F);
993 GLint w010 = (GLint) ((1.0F-a)* b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
994 GLint w110 = (GLint) ( a * b *(1.0F-c) * WEIGHT_SCALE + 0.5F);
995 GLint w001 = (GLint) ((1.0F-a)*(1.0F-b)* c * WEIGHT_SCALE + 0.5F);
996 GLint w101 = (GLint) ( a *(1.0F-b)* c * WEIGHT_SCALE + 0.5F);
997 GLint w011 = (GLint) ((1.0F-a)* b * c * WEIGHT_SCALE + 0.5F);
998 GLint w111 = (GLint) ( a * b * c * WEIGHT_SCALE + 0.5F);
999
1000 GLchan t000[4], t010[4], t001[4], t011[4];
1001 GLchan t100[4], t110[4], t101[4], t111[4];
1002
1003 if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
1004 COPY_CHAN4(t000, tObj->BorderColor);
1005 }
1006 else {
1007 (*img->FetchTexel)(img, i0, j0, k0, (GLvoid *) t000);
1008 if (img->Format == GL_COLOR_INDEX) {
1009 palette_sample(ctx, tObj, t000[0], t000);
1010 }
1011 }
1012 if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
1013 COPY_CHAN4(t100, tObj->BorderColor);
1014 }
1015 else {
1016 (*img->FetchTexel)(img, i1, j0, k0, (GLvoid *) t100);
1017 if (img->Format == GL_COLOR_INDEX) {
1018 palette_sample(ctx, tObj, t100[0], t100);
1019 }
1020 }
1021 if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
1022 COPY_CHAN4(t010, tObj->BorderColor);
1023 }
1024 else {
1025 (*img->FetchTexel)(img, i0, j1, k0, (GLvoid *) t010);
1026 if (img->Format == GL_COLOR_INDEX) {
1027 palette_sample(ctx, tObj, t010[0], t010);
1028 }
1029 }
1030 if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
1031 COPY_CHAN4(t110, tObj->BorderColor);
1032 }
1033 else {
1034 (*img->FetchTexel)(img, i1, j1, k0, (GLvoid *) t110);
1035 if (img->Format == GL_COLOR_INDEX) {
1036 palette_sample(ctx, tObj, t110[0], t110);
1037 }
1038 }
1039
1040 if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
1041 COPY_CHAN4(t001, tObj->BorderColor);
1042 }
1043 else {
1044 (*img->FetchTexel)(img, i0, j0, k1, (GLvoid *) t001);
1045 if (img->Format == GL_COLOR_INDEX) {
1046 palette_sample(ctx, tObj, t001[0], t001);
1047 }
1048 }
1049 if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
1050 COPY_CHAN4(t101, tObj->BorderColor);
1051 }
1052 else {
1053 (*img->FetchTexel)(img, i1, j0, k1, (GLvoid *) t101);
1054 if (img->Format == GL_COLOR_INDEX) {
1055 palette_sample(ctx, tObj, t101[0], t101);
1056 }
1057 }
1058 if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
1059 COPY_CHAN4(t011, tObj->BorderColor);
1060 }
1061 else {
1062 (*img->FetchTexel)(img, i0, j1, k1, (GLvoid *) t011);
1063 if (img->Format == GL_COLOR_INDEX) {
1064 palette_sample(ctx, tObj, t011[0], t011);
1065 }
1066 }
1067 if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
1068 COPY_CHAN4(t111, tObj->BorderColor);
1069 }
1070 else {
1071 (*img->FetchTexel)(img, i1, j1, k1, (GLvoid *) t111);
1072 if (img->Format == GL_COLOR_INDEX) {
1073 palette_sample(ctx, tObj, t111[0], t111);
1074 }
1075 }
1076
1077 rgba[0] = (GLchan) (
1078 (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] +
1079 w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] )
1080 >> WEIGHT_SHIFT);
1081 rgba[1] = (GLchan) (
1082 (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] +
1083 w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] )
1084 >> WEIGHT_SHIFT);
1085 rgba[2] = (GLchan) (
1086 (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] +
1087 w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] )
1088 >> WEIGHT_SHIFT);
1089 rgba[3] = (GLchan) (
1090 (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] +
1091 w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] )
1092 >> WEIGHT_SHIFT);
1093 }
1094 }
1095
1096
1097
1098 static void
1099 sample_3d_nearest_mipmap_nearest(GLcontext *ctx,
1100 const struct gl_texture_object *tObj,
1101 GLfloat s, GLfloat t, GLfloat r,
1102 GLfloat lambda, GLchan rgba[4] )
1103 {
1104 GLint level;
1105 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1106 sample_3d_nearest(ctx, tObj, tObj->Image[level], s, t, r, rgba);
1107 }
1108
1109
1110 static void
1111 sample_3d_linear_mipmap_nearest(GLcontext *ctx,
1112 const struct gl_texture_object *tObj,
1113 GLfloat s, GLfloat t, GLfloat r,
1114 GLfloat lambda, GLchan rgba[4])
1115 {
1116 GLint level;
1117 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1118 sample_3d_linear(ctx, tObj, tObj->Image[level], s, t, r, rgba);
1119 }
1120
1121
1122 static void
1123 sample_3d_nearest_mipmap_linear(GLcontext *ctx,
1124 const struct gl_texture_object *tObj,
1125 GLfloat s, GLfloat t, GLfloat r,
1126 GLfloat lambda, GLchan rgba[4])
1127 {
1128 GLint level;
1129
1130 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1131
1132 if (level >= tObj->_MaxLevel) {
1133 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->_MaxLevel],
1134 s, t, r, rgba);
1135 }
1136 else {
1137 GLchan t0[4], t1[4]; /* texels */
1138 const GLfloat f = FRAC(lambda);
1139 sample_3d_nearest(ctx, tObj, tObj->Image[level ], s, t, r, t0);
1140 sample_3d_nearest(ctx, tObj, tObj->Image[level+1], s, t, r, t1);
1141 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1142 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1143 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1144 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1145 }
1146 }
1147
1148
1149 static void
1150 sample_3d_linear_mipmap_linear(GLcontext *ctx,
1151 const struct gl_texture_object *tObj,
1152 GLfloat s, GLfloat t, GLfloat r,
1153 GLfloat lambda, GLchan rgba[4] )
1154 {
1155 GLint level;
1156
1157 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1158
1159 if (level >= tObj->_MaxLevel) {
1160 sample_3d_linear(ctx, tObj, tObj->Image[tObj->_MaxLevel], s, t, r, rgba);
1161 }
1162 else {
1163 GLchan t0[4], t1[4]; /* texels */
1164 const GLfloat f = FRAC(lambda);
1165 sample_3d_linear(ctx, tObj, tObj->Image[level ], s, t, r, t0);
1166 sample_3d_linear(ctx, tObj, tObj->Image[level+1], s, t, r, t1);
1167 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1168 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1169 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1170 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1171 }
1172 }
1173
1174
1175 static void
1176 sample_nearest_3d(GLcontext *ctx, GLuint texUnit,
1177 const struct gl_texture_object *tObj, GLuint n,
1178 const GLfloat s[], const GLfloat t[],
1179 const GLfloat u[], const GLfloat lambda[],
1180 GLchan rgba[][4])
1181 {
1182 GLuint i;
1183 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
1184 (void) lambda;
1185 for (i=0;i<n;i++) {
1186 sample_3d_nearest(ctx, tObj, image, s[i], t[i], u[i], rgba[i]);
1187 }
1188 }
1189
1190
1191
1192 static void
1193 sample_linear_3d( GLcontext *ctx, GLuint texUnit,
1194 const struct gl_texture_object *tObj, GLuint n,
1195 const GLfloat s[], const GLfloat t[],
1196 const GLfloat u[], const GLfloat lambda[],
1197 GLchan rgba[][4] )
1198 {
1199 GLuint i;
1200 struct gl_texture_image *image = tObj->Image[tObj->BaseLevel];
1201 (void) lambda;
1202 for (i=0;i<n;i++) {
1203 sample_3d_linear(ctx, tObj, image, s[i], t[i], u[i], rgba[i]);
1204 }
1205 }
1206
1207
1208 /*
1209 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1210 * return a texture sample.
1211 */
1212 static void
1213 sample_lambda_3d( GLcontext *ctx, GLuint texUnit,
1214 const struct gl_texture_object *tObj, GLuint n,
1215 const GLfloat s[], const GLfloat t[],
1216 const GLfloat u[], const GLfloat lambda[],
1217 GLchan rgba[][4] )
1218 {
1219 GLuint i;
1220 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
1221
1222 for (i=0;i<n;i++) {
1223
1224 if (lambda[i] > MinMagThresh) {
1225 /* minification */
1226 switch (tObj->MinFilter) {
1227 case GL_NEAREST:
1228 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
1229 s[i], t[i], u[i], rgba[i]);
1230 break;
1231 case GL_LINEAR:
1232 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
1233 s[i], t[i], u[i], rgba[i]);
1234 break;
1235 case GL_NEAREST_MIPMAP_NEAREST:
1236 sample_3d_nearest_mipmap_nearest(ctx, tObj, s[i], t[i], u[i],
1237 lambda[i], rgba[i]);
1238 break;
1239 case GL_LINEAR_MIPMAP_NEAREST:
1240 sample_3d_linear_mipmap_nearest(ctx, tObj, s[i], t[i], u[i],
1241 lambda[i], rgba[i]);
1242 break;
1243 case GL_NEAREST_MIPMAP_LINEAR:
1244 sample_3d_nearest_mipmap_linear(ctx, tObj, s[i], t[i], u[i],
1245 lambda[i], rgba[i]);
1246 break;
1247 case GL_LINEAR_MIPMAP_LINEAR:
1248 sample_3d_linear_mipmap_linear(ctx, tObj, s[i], t[i], u[i],
1249 lambda[i], rgba[i]);
1250 break;
1251 default:
1252 _mesa_problem(NULL, "Bad min filterin sample_3d_texture");
1253 }
1254 }
1255 else {
1256 /* magnification */
1257 switch (tObj->MagFilter) {
1258 case GL_NEAREST:
1259 sample_3d_nearest(ctx, tObj, tObj->Image[tObj->BaseLevel],
1260 s[i], t[i], u[i], rgba[i]);
1261 break;
1262 case GL_LINEAR:
1263 sample_3d_linear(ctx, tObj, tObj->Image[tObj->BaseLevel],
1264 s[i], t[i], u[i], rgba[i]);
1265 break;
1266 default:
1267 _mesa_problem(NULL, "Bad mag filter in sample_3d_texture");
1268 }
1269 }
1270 }
1271 }
1272
1273
1274 /**********************************************************************/
1275 /* Texture Cube Map Sampling Functions */
1276 /**********************************************************************/
1277
1278 /*
1279 * Choose one of six sides of a texture cube map given the texture
1280 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1281 * images.
1282 */
1283 static const struct gl_texture_image **
1284 choose_cube_face(const struct gl_texture_object *texObj,
1285 GLfloat rx, GLfloat ry, GLfloat rz,
1286 GLfloat *newS, GLfloat *newT)
1287 {
1288 /*
1289 major axis
1290 direction target sc tc ma
1291 ---------- ------------------------------- --- --- ---
1292 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1293 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1294 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1295 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1296 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1297 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1298 */
1299 const struct gl_texture_image **imgArray;
1300 const GLfloat arx = ABSF(rx), ary = ABSF(ry), arz = ABSF(rz);
1301 GLfloat sc, tc, ma;
1302
1303 if (arx > ary && arx > arz) {
1304 if (rx >= 0.0F) {
1305 imgArray = (const struct gl_texture_image **) texObj->Image;
1306 sc = -rz;
1307 tc = -ry;
1308 ma = arx;
1309 }
1310 else {
1311 imgArray = (const struct gl_texture_image **) texObj->NegX;
1312 sc = rz;
1313 tc = -ry;
1314 ma = arx;
1315 }
1316 }
1317 else if (ary > arx && ary > arz) {
1318 if (ry >= 0.0F) {
1319 imgArray = (const struct gl_texture_image **) texObj->PosY;
1320 sc = rx;
1321 tc = rz;
1322 ma = ary;
1323 }
1324 else {
1325 imgArray = (const struct gl_texture_image **) texObj->NegY;
1326 sc = rx;
1327 tc = -rz;
1328 ma = ary;
1329 }
1330 }
1331 else {
1332 if (rz > 0.0F) {
1333 imgArray = (const struct gl_texture_image **) texObj->PosZ;
1334 sc = rx;
1335 tc = -ry;
1336 ma = arz;
1337 }
1338 else {
1339 imgArray = (const struct gl_texture_image **) texObj->NegZ;
1340 sc = -rx;
1341 tc = -ry;
1342 ma = arz;
1343 }
1344 }
1345
1346 *newS = ( sc / ma + 1.0F ) * 0.5F;
1347 *newT = ( tc / ma + 1.0F ) * 0.5F;
1348 return imgArray;
1349 }
1350
1351
1352 static void
1353 sample_nearest_cube(GLcontext *ctx, GLuint texUnit,
1354 const struct gl_texture_object *tObj, GLuint n,
1355 const GLfloat s[], const GLfloat t[],
1356 const GLfloat u[], const GLfloat lambda[],
1357 GLchan rgba[][4])
1358 {
1359 GLuint i;
1360 (void) lambda;
1361 for (i = 0; i < n; i++) {
1362 const struct gl_texture_image **images;
1363 GLfloat newS, newT;
1364 images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
1365 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1366 newS, newT, rgba[i]);
1367 }
1368 }
1369
1370
1371 static void
1372 sample_linear_cube(GLcontext *ctx, GLuint texUnit,
1373 const struct gl_texture_object *tObj, GLuint n,
1374 const GLfloat s[], const GLfloat t[],
1375 const GLfloat u[], const GLfloat lambda[],
1376 GLchan rgba[][4])
1377 {
1378 GLuint i;
1379 (void) lambda;
1380 for (i = 0; i < n; i++) {
1381 const struct gl_texture_image **images;
1382 GLfloat newS, newT;
1383 images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT);
1384 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1385 newS, newT, rgba[i]);
1386 }
1387 }
1388
1389
1390 static void
1391 sample_cube_nearest_mipmap_nearest(GLcontext *ctx,
1392 const struct gl_texture_object *tObj,
1393 GLfloat s, GLfloat t, GLfloat u,
1394 GLfloat lambda, GLchan rgba[4])
1395 {
1396 const struct gl_texture_image **images;
1397 GLfloat newS, newT;
1398 GLint level;
1399
1400 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1401
1402 images = choose_cube_face(tObj, s, t, u, &newS, &newT);
1403 sample_2d_nearest(ctx, tObj, images[level], newS, newT, rgba);
1404 }
1405
1406
1407 static void
1408 sample_cube_linear_mipmap_nearest(GLcontext *ctx,
1409 const struct gl_texture_object *tObj,
1410 GLfloat s, GLfloat t, GLfloat u,
1411 GLfloat lambda, GLchan rgba[4])
1412 {
1413 const struct gl_texture_image **images;
1414 GLfloat newS, newT;
1415 GLint level;
1416
1417 COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level);
1418
1419 images = choose_cube_face(tObj, s, t, u, &newS, &newT);
1420 sample_2d_linear(ctx, tObj, images[level], newS, newT, rgba);
1421 }
1422
1423
1424 static void
1425 sample_cube_nearest_mipmap_linear(GLcontext *ctx,
1426 const struct gl_texture_object *tObj,
1427 GLfloat s, GLfloat t, GLfloat u,
1428 GLfloat lambda, GLchan rgba[4])
1429 {
1430 const struct gl_texture_image **images;
1431 GLfloat newS, newT;
1432 GLint level;
1433
1434 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1435
1436 images = choose_cube_face(tObj, s, t, u, &newS, &newT);
1437
1438 if (level >= tObj->_MaxLevel) {
1439 sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel], newS, newT, rgba);
1440 }
1441 else {
1442 GLchan t0[4], t1[4]; /* texels */
1443 const GLfloat f = FRAC(lambda);
1444 sample_2d_nearest(ctx, tObj, images[level ], newS, newT, t0);
1445 sample_2d_nearest(ctx, tObj, images[level+1], newS, newT, t1);
1446 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1447 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1448 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1449 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1450 }
1451 }
1452
1453
1454 static void
1455 sample_cube_linear_mipmap_linear(GLcontext *ctx,
1456 const struct gl_texture_object *tObj,
1457 GLfloat s, GLfloat t, GLfloat u,
1458 GLfloat lambda, GLchan rgba[4])
1459 {
1460 const struct gl_texture_image **images;
1461 GLfloat newS, newT;
1462 GLint level;
1463
1464 COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level);
1465
1466 images = choose_cube_face(tObj, s, t, u, &newS, &newT);
1467
1468 if (level >= tObj->_MaxLevel) {
1469 sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel], newS, newT, rgba);
1470 }
1471 else {
1472 GLchan t0[4], t1[4];
1473 const GLfloat f = FRAC(lambda);
1474 sample_2d_linear(ctx, tObj, images[level ], newS, newT, t0);
1475 sample_2d_linear(ctx, tObj, images[level+1], newS, newT, t1);
1476 rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
1477 rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
1478 rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
1479 rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
1480 }
1481 }
1482
1483
1484 static void
1485 sample_lambda_cube( GLcontext *ctx, GLuint texUnit,
1486 const struct gl_texture_object *tObj, GLuint n,
1487 const GLfloat s[], const GLfloat t[],
1488 const GLfloat u[], const GLfloat lambda[],
1489 GLchan rgba[][4])
1490 {
1491 GLfloat MinMagThresh = SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit];
1492 GLuint i;
1493
1494 for (i = 0; i < n; i++) {
1495 if (lambda[i] > MinMagThresh) {
1496 /* minification */
1497 switch (tObj->MinFilter) {
1498 case GL_NEAREST:
1499 {
1500 const struct gl_texture_image **images;
1501 GLfloat newS, newT;
1502 images = choose_cube_face(tObj, s[i], t[i], u[i],
1503 &newS, &newT);
1504 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1505 newS, newT, rgba[i]);
1506 }
1507 break;
1508 case GL_LINEAR:
1509 {
1510 const struct gl_texture_image **images;
1511 GLfloat newS, newT;
1512 images = choose_cube_face(tObj, s[i], t[i], u[i],
1513 &newS, &newT);
1514 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1515 newS, newT, rgba[i]);
1516 }
1517 break;
1518 case GL_NEAREST_MIPMAP_NEAREST:
1519 sample_cube_nearest_mipmap_nearest(ctx, tObj, s[i], t[i], u[i],
1520 lambda[i], rgba[i]);
1521 break;
1522 case GL_LINEAR_MIPMAP_NEAREST:
1523 sample_cube_linear_mipmap_nearest(ctx, tObj, s[i], t[i], u[i],
1524 lambda[i], rgba[i]);
1525 break;
1526 case GL_NEAREST_MIPMAP_LINEAR:
1527 sample_cube_nearest_mipmap_linear(ctx, tObj, s[i], t[i], u[i],
1528 lambda[i], rgba[i]);
1529 break;
1530 case GL_LINEAR_MIPMAP_LINEAR:
1531 sample_cube_linear_mipmap_linear(ctx, tObj, s[i], t[i], u[i],
1532 lambda[i], rgba[i]);
1533 break;
1534 default:
1535 _mesa_problem(NULL, "Bad min filter in sample_lambda_cube");
1536 }
1537 }
1538 else {
1539 /* magnification */
1540 const struct gl_texture_image **images;
1541 GLfloat newS, newT;
1542 images = choose_cube_face(tObj, s[i], t[i], u[i],
1543 &newS, &newT);
1544 switch (tObj->MagFilter) {
1545 case GL_NEAREST:
1546 sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
1547 newS, newT, rgba[i]);
1548 break;
1549 case GL_LINEAR:
1550 sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
1551 newS, newT, rgba[i]);
1552 break;
1553 default:
1554 _mesa_problem(NULL, "Bad mag filter in sample_lambda_cube");
1555 }
1556 }
1557 }
1558 }
1559
1560 static void
1561 null_sample_func( GLcontext *ctx, GLuint texUnit,
1562 const struct gl_texture_object *tObj, GLuint n,
1563 const GLfloat s[], const GLfloat t[],
1564 const GLfloat u[], const GLfloat lambda[],
1565 GLchan rgba[][4])
1566 {
1567 }
1568
1569 /**********************************************************************/
1570 /* Texture Sampling Setup */
1571 /**********************************************************************/
1572
1573
1574 /*
1575 * Setup the texture sampling function for this texture object.
1576 */
1577 void
1578 _swrast_choose_texture_sample_func( GLcontext *ctx, GLuint texUnit,
1579 const struct gl_texture_object *t )
1580 {
1581 SWcontext *swrast = SWRAST_CONTEXT(ctx);
1582
1583 if (!t->Complete) {
1584 swrast->TextureSample[texUnit] = null_sample_func;
1585 }
1586 else {
1587 GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
1588
1589 if (needLambda) {
1590 /* Compute min/mag filter threshold */
1591 if (t->MagFilter == GL_LINEAR
1592 && (t->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
1593 t->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
1594 swrast->_MinMagThresh[texUnit] = 0.5F;
1595 }
1596 else {
1597 swrast->_MinMagThresh[texUnit] = 0.0F;
1598 }
1599 }
1600
1601 switch (t->Dimensions) {
1602 case 1:
1603 if (needLambda) {
1604 swrast->TextureSample[texUnit] = sample_lambda_1d;
1605 }
1606 else if (t->MinFilter==GL_LINEAR) {
1607 swrast->TextureSample[texUnit] = sample_linear_1d;
1608 }
1609 else {
1610 ASSERT(t->MinFilter==GL_NEAREST);
1611 swrast->TextureSample[texUnit] = sample_nearest_1d;
1612 }
1613 break;
1614 case 2:
1615 if (needLambda) {
1616 swrast->TextureSample[texUnit] = sample_lambda_2d;
1617 }
1618 else if (t->MinFilter==GL_LINEAR) {
1619 swrast->TextureSample[texUnit] = sample_linear_2d;
1620 }
1621 else {
1622 GLint baseLevel = t->BaseLevel;
1623 ASSERT(t->MinFilter==GL_NEAREST);
1624 if (t->WrapS == GL_REPEAT &&
1625 t->WrapT == GL_REPEAT &&
1626 t->Image[baseLevel]->Border == 0 &&
1627 t->Image[baseLevel]->Format == GL_RGB &&
1628 t->Image[baseLevel]->Type == CHAN_TYPE) {
1629 swrast->TextureSample[texUnit] = opt_sample_rgb_2d;
1630 }
1631 else if (t->WrapS == GL_REPEAT &&
1632 t->WrapT == GL_REPEAT &&
1633 t->Image[baseLevel]->Border == 0 &&
1634 t->Image[baseLevel]->Format==GL_RGBA &&
1635 t->Image[baseLevel]->Type == CHAN_TYPE) {
1636 swrast->TextureSample[texUnit] = opt_sample_rgba_2d;
1637 }
1638 else
1639 swrast->TextureSample[texUnit] = sample_nearest_2d;
1640 }
1641 break;
1642 case 3:
1643 if (needLambda) {
1644 swrast->TextureSample[texUnit] = sample_lambda_3d;
1645 }
1646 else if (t->MinFilter==GL_LINEAR) {
1647 swrast->TextureSample[texUnit] = sample_linear_3d;
1648 }
1649 else {
1650 ASSERT(t->MinFilter==GL_NEAREST);
1651 swrast->TextureSample[texUnit] = sample_nearest_3d;
1652 }
1653 break;
1654 case 6: /* cube map */
1655 if (needLambda) {
1656 swrast->TextureSample[texUnit] = sample_lambda_cube;
1657 }
1658 else if (t->MinFilter==GL_LINEAR) {
1659 swrast->TextureSample[texUnit] = sample_linear_cube;
1660 }
1661 else {
1662 ASSERT(t->MinFilter==GL_NEAREST);
1663 swrast->TextureSample[texUnit] = sample_nearest_cube;
1664 }
1665 break;
1666 default:
1667 _mesa_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
1668 }
1669 }
1670 }
1671
1672
1673 #define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
1674 #define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
1675
1676 static INLINE void
1677 texture_combine(const GLcontext *ctx,
1678 const struct gl_texture_unit *textureUnit,
1679 GLuint n,
1680 CONST GLchan (*primary_rgba)[4],
1681 CONST GLchan (*texel)[4],
1682 GLchan (*rgba)[4])
1683 {
1684 GLchan ccolor [3][3*MAX_WIDTH][4];
1685 const GLchan (*argRGB [3])[4];
1686 const GLchan (*argA [3])[4];
1687 GLuint i, j;
1688 const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
1689 const GLuint Ashift = textureUnit->CombineScaleShiftA;
1690
1691 ASSERT(ctx->Extensions.EXT_texture_env_combine);
1692
1693 for (j = 0; j < 3; j++) {
1694 switch (textureUnit->CombineSourceA[j]) {
1695 case GL_TEXTURE:
1696 argA[j] = texel;
1697 break;
1698 case GL_PRIMARY_COLOR_EXT:
1699 argA[j] = primary_rgba;
1700 break;
1701 case GL_PREVIOUS_EXT:
1702 argA[j] = (const GLchan (*)[4]) rgba;
1703 break;
1704 case GL_CONSTANT_EXT:
1705 {
1706 GLchan alpha, (*c)[4] = ccolor[j];
1707 UNCLAMPED_FLOAT_TO_CHAN(alpha, textureUnit->EnvColor[3]);
1708 for (i = 0; i < n; i++)
1709 c[i][ACOMP] = alpha;
1710 argA[j] = (const GLchan (*)[4]) ccolor[j];
1711 }
1712 break;
1713 default:
1714 _mesa_problem(NULL, "invalid combine source");
1715 }
1716
1717 switch (textureUnit->CombineSourceRGB[j]) {
1718 case GL_TEXTURE:
1719 argRGB[j] = texel;
1720 break;
1721 case GL_PRIMARY_COLOR_EXT:
1722 argRGB[j] = primary_rgba;
1723 break;
1724 case GL_PREVIOUS_EXT:
1725 argRGB[j] = (const GLchan (*)[4]) rgba;
1726 break;
1727 case GL_CONSTANT_EXT:
1728 {
1729 GLchan (*c)[4] = ccolor[j];
1730 GLchan red, green, blue;
1731 UNCLAMPED_FLOAT_TO_CHAN(red, textureUnit->EnvColor[0]);
1732 UNCLAMPED_FLOAT_TO_CHAN(green, textureUnit->EnvColor[1]);
1733 UNCLAMPED_FLOAT_TO_CHAN(blue, textureUnit->EnvColor[2]);
1734 for (i = 0; i < n; i++) {
1735 c[i][RCOMP] = red;
1736 c[i][GCOMP] = green;
1737 c[i][BCOMP] = blue;
1738 }
1739 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
1740 }
1741 break;
1742 default:
1743 _mesa_problem(NULL, "invalid combine source");
1744 }
1745
1746 if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
1747 const GLchan (*src)[4] = argRGB[j];
1748 GLchan (*dst)[4] = ccolor[j];
1749
1750 argRGB[j] = (const GLchan (*)[4]) ccolor[j];
1751
1752 if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) {
1753 for (i = 0; i < n; i++) {
1754 dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP];
1755 dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP];
1756 dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP];
1757 }
1758 }
1759 else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) {
1760 src = (const GLchan (*)[4]) argA[j];
1761 for (i = 0; i < n; i++) {
1762 dst[i][RCOMP] = src[i][ACOMP];
1763 dst[i][GCOMP] = src[i][ACOMP];
1764 dst[i][BCOMP] = src[i][ACOMP];
1765 }
1766 }
1767 else { /* GL_ONE_MINUS_SRC_ALPHA */
1768 src = (const GLchan (*)[4]) argA[j];
1769 for (i = 0; i < n; i++) {
1770 dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP];
1771 dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP];
1772 dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP];
1773 }
1774 }
1775 }
1776
1777 if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) {
1778 const GLchan (*src)[4] = argA[j];
1779 GLchan (*dst)[4] = ccolor[j];
1780 argA[j] = (const GLchan (*)[4]) ccolor[j];
1781 for (i = 0; i < n; i++) {
1782 dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP];
1783 }
1784 }
1785
1786 if (textureUnit->CombineModeRGB == GL_REPLACE &&
1787 textureUnit->CombineModeA == GL_REPLACE) {
1788 break; /* done, we need only arg0 */
1789 }
1790
1791 if (j == 1 &&
1792 textureUnit->CombineModeRGB != GL_INTERPOLATE_EXT &&
1793 textureUnit->CombineModeA != GL_INTERPOLATE_EXT) {
1794 break; /* arg0 and arg1 are done. we don't need arg2. */
1795 }
1796 }
1797
1798 switch (textureUnit->CombineModeRGB) {
1799 case GL_REPLACE:
1800 {
1801 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
1802 if (RGBshift) {
1803 for (i = 0; i < n; i++) {
1804 GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift;
1805 GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift;
1806 GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift;
1807 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
1808 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
1809 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
1810 }
1811 }
1812 else {
1813 for (i = 0; i < n; i++) {
1814 rgba[i][RCOMP] = arg0[i][RCOMP];
1815 rgba[i][GCOMP] = arg0[i][GCOMP];
1816 rgba[i][BCOMP] = arg0[i][BCOMP];
1817 }
1818 }
1819 }
1820 break;
1821 case GL_MODULATE:
1822 {
1823 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
1824 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
1825 const GLint shift = 8 - RGBshift;
1826 for (i = 0; i < n; i++) {
1827 GLuint r = PROD(arg0[i][0], arg1[i][RCOMP]) >> shift;
1828 GLuint g = PROD(arg0[i][1], arg1[i][GCOMP]) >> shift;
1829 GLuint b = PROD(arg0[i][2], arg1[i][BCOMP]) >> shift;
1830 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1831 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1832 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1833 }
1834 }
1835 break;
1836 case GL_ADD:
1837 {
1838 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
1839 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
1840 for (i = 0; i < n; i++) {
1841 GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift;
1842 GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift;
1843 GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift;
1844 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1845 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1846 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1847 }
1848 }
1849 break;
1850 case GL_ADD_SIGNED_EXT:
1851 {
1852 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
1853 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
1854 for (i = 0; i < n; i++) {
1855 GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] - 128;
1856 GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] - 128;
1857 GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] - 128;
1858 r = (r < 0) ? 0 : r << RGBshift;
1859 g = (g < 0) ? 0 : g << RGBshift;
1860 b = (b < 0) ? 0 : b << RGBshift;
1861 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1862 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1863 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1864 }
1865 }
1866 break;
1867 case GL_INTERPOLATE_EXT:
1868 {
1869 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
1870 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
1871 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
1872 const GLint shift = 8 - RGBshift;
1873 for (i = 0; i < n; i++) {
1874 GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP])
1875 + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP]))
1876 >> shift;
1877 GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP])
1878 + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP]))
1879 >> shift;
1880 GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP])
1881 + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP]))
1882 >> shift;
1883 rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX);
1884 rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX);
1885 rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX);
1886 }
1887 }
1888 break;
1889 case GL_DOT3_RGB_EXT:
1890 case GL_DOT3_RGBA_EXT:
1891 {
1892 const GLubyte (*arg0)[4] = (const GLubyte (*)[4]) argRGB[0];
1893 const GLubyte (*arg1)[4] = (const GLubyte (*)[4]) argRGB[1];
1894 /* ATI's EXT extension has a constant scale by 4. The ARB
1895 * one will likely remove this restriction, and we should
1896 * drop the EXT extension in favour of the ARB one.
1897 */
1898 for (i = 0; i < n; i++) {
1899 GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - 128,
1900 (GLint)arg1[i][RCOMP] - 128) +
1901 S_PROD((GLint)arg0[i][GCOMP] - 128,
1902 (GLint)arg1[i][GCOMP] - 128) +
1903 S_PROD((GLint)arg0[i][BCOMP] - 128,
1904 (GLint)arg1[i][BCOMP] - 128)) >> 6;
1905 rgba[i][RCOMP] = (GLubyte) CLAMP(dot, 0, 255);
1906 rgba[i][GCOMP] = (GLubyte) CLAMP(dot, 0, 255);
1907 rgba[i][BCOMP] = (GLubyte) CLAMP(dot, 0, 255);
1908 }
1909 }
1910 break;
1911 default:
1912 _mesa_problem(NULL, "invalid combine mode");
1913 }
1914
1915 switch (textureUnit->CombineModeA) {
1916 case GL_REPLACE:
1917 {
1918 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
1919 if (Ashift) {
1920 for (i = 0; i < n; i++) {
1921 GLuint a = (GLuint) arg0[i][ACOMP] << Ashift;
1922 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
1923 }
1924 }
1925 else {
1926 for (i = 0; i < n; i++) {
1927 rgba[i][ACOMP] = arg0[i][ACOMP];
1928 }
1929 }
1930 }
1931 break;
1932 case GL_MODULATE:
1933 {
1934 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
1935 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
1936 const GLint shift = 8 - Ashift;
1937 for (i = 0; i < n; i++) {
1938 GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift);
1939 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
1940 }
1941 }
1942 break;
1943 case GL_ADD:
1944 {
1945 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
1946 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
1947 for (i = 0; i < n; i++) {
1948 GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift;
1949 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
1950 }
1951 }
1952 break;
1953 case GL_ADD_SIGNED_EXT:
1954 {
1955 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
1956 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
1957 for (i = 0; i < n; i++) {
1958 GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] - 128;
1959 a = (a < 0) ? 0 : a << Ashift;
1960 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
1961 }
1962 }
1963 break;
1964 case GL_INTERPOLATE_EXT:
1965 {
1966 const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
1967 const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
1968 const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
1969 const GLint shift = 8 - Ashift;
1970 for (i=0; i<n; i++) {
1971 GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP])
1972 + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP]))
1973 >> shift;
1974 rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX);
1975 }
1976 }
1977 break;
1978 default:
1979 _mesa_problem(NULL, "invalid combine mode");
1980 }
1981
1982 /* Fix the alpha component for GL_DOT3_RGBA_EXT combining.
1983 */
1984 if (textureUnit->CombineModeRGB == GL_DOT3_RGBA_EXT) {
1985 for (i = 0; i < n; i++) {
1986 rgba[i][ACOMP] = rgba[i][RCOMP];
1987 }
1988 }
1989 }
1990 #undef PROD
1991
1992
1993
1994 /**********************************************************************/
1995 /* Texture Application */
1996 /**********************************************************************/
1997
1998
1999 /*
2000 * Combine incoming fragment color with texel color to produce output color.
2001 * Input: textureUnit - pointer to texture unit to apply
2002 * format - base internal texture format
2003 * n - number of fragments
2004 * primary_rgba - primary colors (may alias rgba for single texture)
2005 * texels - array of texel colors
2006 * InOut: rgba - incoming fragment colors modified by texel colors
2007 * according to the texture environment mode.
2008 */
2009 static void
2010 apply_texture( const GLcontext *ctx,
2011 const struct gl_texture_unit *texUnit,
2012 GLuint n,
2013 CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
2014 GLchan rgba[][4] )
2015 {
2016 GLint baseLevel;
2017 GLuint i;
2018 GLint Rc, Gc, Bc, Ac;
2019 GLenum format;
2020
2021 ASSERT(texUnit);
2022 ASSERT(texUnit->_Current);
2023
2024 baseLevel = texUnit->_Current->BaseLevel;
2025 ASSERT(texUnit->_Current->Image[baseLevel]);
2026
2027 format = texUnit->_Current->Image[baseLevel]->Format;
2028
2029 if (format==GL_COLOR_INDEX || format==GL_DEPTH_COMPONENT) {
2030 format = GL_RGBA; /* XXXX a hack! */
2031 }
2032
2033 switch (texUnit->EnvMode) {
2034 case GL_REPLACE:
2035 switch (format) {
2036 case GL_ALPHA:
2037 for (i=0;i<n;i++) {
2038 /* Cv = Cf */
2039 /* Av = At */
2040 rgba[i][ACOMP] = texel[i][ACOMP];
2041 }
2042 break;
2043 case GL_LUMINANCE:
2044 for (i=0;i<n;i++) {
2045 /* Cv = Lt */
2046 GLchan Lt = texel[i][RCOMP];
2047 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
2048 /* Av = Af */
2049 }
2050 break;
2051 case GL_LUMINANCE_ALPHA:
2052 for (i=0;i<n;i++) {
2053 GLchan Lt = texel[i][RCOMP];
2054 /* Cv = Lt */
2055 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt;
2056 /* Av = At */
2057 rgba[i][ACOMP] = texel[i][ACOMP];
2058 }
2059 break;
2060 case GL_INTENSITY:
2061 for (i=0;i<n;i++) {
2062 /* Cv = It */
2063 GLchan It = texel[i][RCOMP];
2064 rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It;
2065 /* Av = It */
2066 rgba[i][ACOMP] = It;
2067 }
2068 break;
2069 case GL_RGB:
2070 for (i=0;i<n;i++) {
2071 /* Cv = Ct */
2072 rgba[i][RCOMP] = texel[i][RCOMP];
2073 rgba[i][GCOMP] = texel[i][GCOMP];
2074 rgba[i][BCOMP] = texel[i][BCOMP];
2075 /* Av = Af */
2076 }
2077 break;
2078 case GL_RGBA:
2079 for (i=0;i<n;i++) {
2080 /* Cv = Ct */
2081 rgba[i][RCOMP] = texel[i][RCOMP];
2082 rgba[i][GCOMP] = texel[i][GCOMP];
2083 rgba[i][BCOMP] = texel[i][BCOMP];
2084 /* Av = At */
2085 rgba[i][ACOMP] = texel[i][ACOMP];
2086 }
2087 break;
2088 default:
2089 _mesa_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
2090 return;
2091 }
2092 break;
2093
2094 case GL_MODULATE:
2095 switch (format) {
2096 case GL_ALPHA:
2097 for (i=0;i<n;i++) {
2098 /* Cv = Cf */
2099 /* Av = AfAt */
2100 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2101 }
2102 break;
2103 case GL_LUMINANCE:
2104 for (i=0;i<n;i++) {
2105 /* Cv = LtCf */
2106 GLchan Lt = texel[i][RCOMP];
2107 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
2108 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
2109 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
2110 /* Av = Af */
2111 }
2112 break;
2113 case GL_LUMINANCE_ALPHA:
2114 for (i=0;i<n;i++) {
2115 /* Cv = CfLt */
2116 GLchan Lt = texel[i][RCOMP];
2117 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt );
2118 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt );
2119 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt );
2120 /* Av = AfAt */
2121 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2122 }
2123 break;
2124 case GL_INTENSITY:
2125 for (i=0;i<n;i++) {
2126 /* Cv = CfIt */
2127 GLchan It = texel[i][RCOMP];
2128 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
2129 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
2130 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
2131 /* Av = AfIt */
2132 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
2133 }
2134 break;
2135 case GL_RGB:
2136 for (i=0;i<n;i++) {
2137 /* Cv = CfCt */
2138 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
2139 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
2140 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
2141 /* Av = Af */
2142 }
2143 break;
2144 case GL_RGBA:
2145 for (i=0;i<n;i++) {
2146 /* Cv = CfCt */
2147 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
2148 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
2149 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
2150 /* Av = AfAt */
2151 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
2152 }
2153 break;
2154 default:
2155 _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
2156 return;
2157 }
2158 break;
2159
2160 case GL_DECAL:
2161 switch (format) {
2162 case GL_ALPHA:
2163 case GL_LUMINANCE:
2164 case GL_LUMINANCE_ALPHA:
2165 case GL_INTENSITY:
2166 /* undefined */
2167 break;
2168 case GL_RGB:
2169 for (i=0;i<n;i++) {
2170 /* Cv = Ct */
2171 rgba[i][RCOMP] = texel[i][RCOMP];
2172 rgba[i][GCOMP] = texel[i][GCOMP];
2173 rgba[i][BCOMP] = texel[i][BCOMP];
2174 /* Av = Af */
2175 }
2176 break;
2177 case GL_RGBA:
2178 for (i=0;i<n;i++) {
2179 /* Cv = Cf(1-At) + CtAt */
2180 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
2181 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
2182 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
2183 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
2184 /* Av = Af */
2185 }
2186 break;
2187 default:
2188 _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
2189 return;
2190 }
2191 break;
2192
2193 case GL_BLEND:
2194 Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
2195 Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
2196 Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
2197 Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
2198 switch (format) {
2199 case GL_ALPHA:
2200 for (i=0;i<n;i++) {
2201 /* Cv = Cf */
2202 /* Av = AfAt */
2203 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2204 }
2205 break;
2206 case GL_LUMINANCE:
2207 for (i=0;i<n;i++) {
2208 /* Cv = Cf(1-Lt) + CcLt */
2209 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
2210 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
2211 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
2212 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
2213 /* Av = Af */
2214 }
2215 break;
2216 case GL_LUMINANCE_ALPHA:
2217 for (i=0;i<n;i++) {
2218 /* Cv = Cf(1-Lt) + CcLt */
2219 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
2220 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
2221 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
2222 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
2223 /* Av = AfAt */
2224 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
2225 }
2226 break;
2227 case GL_INTENSITY:
2228 for (i=0;i<n;i++) {
2229 /* Cv = Cf(1-It) + CcLt */
2230 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
2231 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
2232 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
2233 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
2234 /* Av = Af(1-It) + Ac*It */
2235 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
2236 }
2237 break;
2238 case GL_RGB:
2239 for (i=0;i<n;i++) {
2240 /* Cv = Cf(1-Ct) + CcCt */
2241 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
2242 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
2243 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
2244 /* Av = Af */
2245 }
2246 break;
2247 case GL_RGBA:
2248 for (i=0;i<n;i++) {
2249 /* Cv = Cf(1-Ct) + CcCt */
2250 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
2251 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
2252 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
2253 /* Av = AfAt */
2254 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
2255 }
2256 break;
2257 default:
2258 _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
2259 return;
2260 }
2261 break;
2262
2263 case GL_ADD: /* GL_EXT_texture_add_env */
2264 switch (format) {
2265 case GL_ALPHA:
2266 for (i=0;i<n;i++) {
2267 /* Rv = Rf */
2268 /* Gv = Gf */
2269 /* Bv = Bf */
2270 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2271 }
2272 break;
2273 case GL_LUMINANCE:
2274 for (i=0;i<n;i++) {
2275 GLuint Lt = texel[i][RCOMP];
2276 GLuint r = rgba[i][RCOMP] + Lt;
2277 GLuint g = rgba[i][GCOMP] + Lt;
2278 GLuint b = rgba[i][BCOMP] + Lt;
2279 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2280 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2281 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2282 /* Av = Af */
2283 }
2284 break;
2285 case GL_LUMINANCE_ALPHA:
2286 for (i=0;i<n;i++) {
2287 GLuint Lt = texel[i][RCOMP];
2288 GLuint r = rgba[i][RCOMP] + Lt;
2289 GLuint g = rgba[i][GCOMP] + Lt;
2290 GLuint b = rgba[i][BCOMP] + Lt;
2291 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2292 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2293 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2294 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2295 }
2296 break;
2297 case GL_INTENSITY:
2298 for (i=0;i<n;i++) {
2299 GLchan It = texel[i][RCOMP];
2300 GLuint r = rgba[i][RCOMP] + It;
2301 GLuint g = rgba[i][GCOMP] + It;
2302 GLuint b = rgba[i][BCOMP] + It;
2303 GLuint a = rgba[i][ACOMP] + It;
2304 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2305 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2306 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2307 rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
2308 }
2309 break;
2310 case GL_RGB:
2311 for (i=0;i<n;i++) {
2312 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
2313 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
2314 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
2315 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2316 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2317 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2318 /* Av = Af */
2319 }
2320 break;
2321 case GL_RGBA:
2322 for (i=0;i<n;i++) {
2323 GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
2324 GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
2325 GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
2326 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
2327 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
2328 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
2329 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
2330 }
2331 break;
2332 default:
2333 _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
2334 return;
2335 }
2336 break;
2337
2338 case GL_COMBINE_EXT:
2339 texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
2340 break;
2341
2342 default:
2343 _mesa_problem(ctx, "Bad env mode in apply_texture");
2344 return;
2345 }
2346 }
2347
2348
2349
2350 /*
2351 * Sample a shadow/depth texture.
2352 * Input: ctx - context
2353 * texUnit - the texture unit
2354 * n - number of samples
2355 * s,t,r - array [n] of texture coordinates
2356 * In/Out: rgba - array [n] of texel colors.
2357 */
2358 static void
2359 sample_depth_texture(const GLcontext *ctx,
2360 const struct gl_texture_unit *texUnit,
2361 GLuint n,
2362 const GLfloat s[], const GLfloat t[], const GLfloat r[],
2363 GLchan texel[][4])
2364 {
2365 const struct gl_texture_object *texObj = texUnit->_Current;
2366 const GLint baseLevel = texObj->BaseLevel;
2367 const struct gl_texture_image *texImage = texObj->Image[baseLevel];
2368 const GLuint width = texImage->Width;
2369 const GLuint height = texImage->Height;
2370 const GLchan ambient = texObj->ShadowAmbient;
2371 GLboolean lequal, gequal;
2372
2373 if (texObj->Dimensions != 2) {
2374 _mesa_problem(ctx, "only 2-D depth textures supported at this time");
2375 return;
2376 }
2377
2378 if (texObj->MinFilter != texObj->MagFilter) {
2379 _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
2380 return;
2381 }
2382
2383 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2384 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2385 * isn't a depth texture.
2386 */
2387 if (texImage->Format != GL_DEPTH_COMPONENT) {
2388 _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2389 return;
2390 }
2391
2392 if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2393 lequal = GL_TRUE;
2394 gequal = GL_FALSE;
2395 }
2396 else {
2397 lequal = GL_FALSE;
2398 gequal = GL_TRUE;
2399 }
2400
2401 if (texObj->MagFilter == GL_NEAREST) {
2402 GLuint i;
2403 for (i = 0; i < n; i++) {
2404 GLfloat depthSample;
2405 GLint col, row;
2406 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, s[i], width, col);
2407 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, t[i], height, row);
2408 depthSample = *((const GLfloat *) texImage->Data + row * width + col);
2409 if ((depthSample <= r[i] && lequal) ||
2410 (depthSample >= r[i] && gequal)) {
2411 texel[i][RCOMP] = ambient;
2412 texel[i][GCOMP] = ambient;
2413 texel[i][BCOMP] = ambient;
2414 texel[i][ACOMP] = CHAN_MAX;
2415 }
2416 else {
2417 texel[i][RCOMP] = CHAN_MAX;
2418 texel[i][GCOMP] = CHAN_MAX;
2419 texel[i][BCOMP] = CHAN_MAX;
2420 texel[i][ACOMP] = CHAN_MAX;
2421 }
2422 }
2423 }
2424 else {
2425 GLuint i;
2426 ASSERT(texObj->MagFilter == GL_LINEAR);
2427 for (i = 0; i < n; i++) {
2428 GLfloat depth00, depth01, depth10, depth11;
2429 GLint i0, i1, j0, j1;
2430 GLfloat u, v;
2431 GLuint useBorderTexel;
2432
2433 COMPUTE_LINEAR_TEXEL_LOCATIONS(texObj->WrapS, s[i], u, width, i0, i1);
2434 COMPUTE_LINEAR_TEXEL_LOCATIONS(texObj->WrapT, t[i], v, height,j0, j1);
2435
2436 useBorderTexel = 0;
2437 if (texImage->Border) {
2438 i0 += texImage->Border;
2439 i1 += texImage->Border;
2440 j0 += texImage->Border;
2441 j1 += texImage->Border;
2442 }
2443 else {
2444 if (i0 < 0 || i0 >= width) useBorderTexel |= I0BIT;
2445 if (i1 < 0 || i1 >= width) useBorderTexel |= I1BIT;
2446 if (j0 < 0 || j0 >= height) useBorderTexel |= J0BIT;
2447 if (j1 < 0 || j1 >= height) useBorderTexel |= J1BIT;
2448 }
2449
2450 /* get four depth samples from the texture */
2451 if (useBorderTexel & (I0BIT | J0BIT)) {
2452 depth00 = 1.0;
2453 }
2454 else {
2455 depth00 = *((const GLfloat *) texImage->Data + j0 * width + i0);
2456 }
2457 if (useBorderTexel & (I1BIT | J0BIT)) {
2458 depth10 = 1.0;
2459 }
2460 else {
2461 depth10 = *((const GLfloat *) texImage->Data + j0 * width + i1);
2462 }
2463 if (useBorderTexel & (I0BIT | J1BIT)) {
2464 depth01 = 1.0;
2465 }
2466 else {
2467 depth01 = *((const GLfloat *) texImage->Data + j1 * width + i0);
2468 }
2469 if (useBorderTexel & (I1BIT | J1BIT)) {
2470 depth11 = 1.0;
2471 }
2472 else {
2473 depth11 = *((const GLfloat *) texImage->Data + j1 * width + i1);
2474 }
2475
2476 if (0) {
2477 /* compute a single weighted depth sample and do one comparison */
2478 const GLfloat a = FRAC(u);
2479 const GLfloat b = FRAC(v);
2480 const GLfloat w00 = (1.0F - a) * (1.0F - b);
2481 const GLfloat w10 = ( a) * (1.0F - b);
2482 const GLfloat w01 = (1.0F - a) * ( b);
2483 const GLfloat w11 = ( a) * ( b);
2484 const GLfloat depthSample = w00 * depth00 + w10 * depth10
2485 + w01 * depth01 + w11 * depth11;
2486 if ((depthSample <= r[i] && lequal) ||
2487 (depthSample >= r[i] && gequal)) {
2488 texel[i][RCOMP] = ambient;
2489 texel[i][GCOMP] = ambient;
2490 texel[i][BCOMP] = ambient;
2491 texel[i][ACOMP] = CHAN_MAX;
2492 }
2493 else {
2494 texel[i][RCOMP] = CHAN_MAX;
2495 texel[i][GCOMP] = CHAN_MAX;
2496 texel[i][BCOMP] = CHAN_MAX;
2497 texel[i][ACOMP] = CHAN_MAX;
2498 }
2499 }
2500 else {
2501 /* Do four depth/R comparisons and compute a weighted result.
2502 * If this touches on somebody's I.P., I'll remove this code
2503 * upon request.
2504 */
2505 const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
2506 GLfloat luminance = CHAN_MAXF;
2507 GLchan lum;
2508 if (lequal) {
2509 if (depth00 <= r[i]) luminance -= d;
2510 if (depth01 <= r[i]) luminance -= d;
2511 if (depth10 <= r[i]) luminance -= d;
2512 if (depth11 <= r[i]) luminance -= d;
2513 }
2514 else {
2515 if (depth00 >= r[i]) luminance -= d;
2516 if (depth01 >= r[i]) luminance -= d;
2517 if (depth10 >= r[i]) luminance -= d;
2518 if (depth11 >= r[i]) luminance -= d;
2519 }
2520 lum = (GLchan) luminance;
2521 texel[i][RCOMP] = lum;
2522 texel[i][GCOMP] = lum;
2523 texel[i][BCOMP] = lum;
2524 texel[i][ACOMP] = CHAN_MAX;
2525 }
2526 }
2527 }
2528 }
2529
2530
2531 #if 0
2532 /*
2533 * Experimental depth texture sampling function.
2534 */
2535 static void
2536 sample_depth_texture2(const GLcontext *ctx,
2537 const struct gl_texture_unit *texUnit,
2538 GLuint n,
2539 const GLfloat s[], const GLfloat t[], const GLfloat r[],
2540 GLchan texel[][4])
2541 {
2542 const struct gl_texture_object *texObj = texUnit->_Current;
2543 const GLint baseLevel = texObj->BaseLevel;
2544 const struct gl_texture_image *texImage = texObj->Image[baseLevel];
2545 const GLuint width = texImage->Width;
2546 const GLuint height = texImage->Height;
2547 const GLchan ambient = texObj->ShadowAmbient;
2548 GLboolean lequal, gequal;
2549
2550 if (texObj->Dimensions != 2) {
2551 _mesa_problem(ctx, "only 2-D depth textures supported at this time");
2552 return;
2553 }
2554
2555 if (texObj->MinFilter != texObj->MagFilter) {
2556 _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
2557 return;
2558 }
2559
2560 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2561 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2562 * isn't a depth texture.
2563 */
2564 if (texImage->Format != GL_DEPTH_COMPONENT) {
2565 _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2566 return;
2567 }
2568
2569 if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
2570 lequal = GL_TRUE;
2571 gequal = GL_FALSE;
2572 }
2573 else {
2574 lequal = GL_FALSE;
2575 gequal = GL_TRUE;
2576 }
2577
2578 {
2579 GLuint i;
2580 for (i = 0; i < n; i++) {
2581 const GLint K = 3;
2582 GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
2583 GLfloat w;
2584 GLchan lum;
2585 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, s[i], width, col);
2586 COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, t[i], height, row);
2587
2588 imin = col - K;
2589 imax = col + K;
2590 jmin = row - K;
2591 jmax = row + K;
2592
2593 if (imin < 0) imin = 0;
2594 if (imax >= width) imax = width - 1;
2595 if (jmin < 0) jmin = 0;
2596 if (jmax >= height) jmax = height - 1;
2597
2598 samples = (imax - imin + 1) * (jmax - jmin + 1);
2599 count = 0;
2600 for (jj = jmin; jj <= jmax; jj++) {
2601 for (ii = imin; ii <= imax; ii++) {
2602 GLfloat depthSample = *((const GLfloat *) texImage->Data
2603 + jj * width + ii);
2604 if ((depthSample <= r[i] && lequal) ||
2605 (depthSample >= r[i] && gequal)) {
2606 count++;
2607 }
2608 }
2609 }
2610
2611 w = (GLfloat) count / (GLfloat) samples;
2612 w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
2613 lum = (GLint) w;
2614
2615 texel[i][RCOMP] = lum;
2616 texel[i][GCOMP] = lum;
2617 texel[i][BCOMP] = lum;
2618 texel[i][ACOMP] = CHAN_MAX;
2619 }
2620 }
2621 }
2622 #endif
2623
2624
2625 /*
2626 * Apply a unit of texture mapping to the incoming fragments.
2627 */
2628 void
2629 _swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
2630 const GLfloat s[], const GLfloat t[],
2631 const GLfloat r[], GLfloat lambda[],
2632 CONST GLchan primary_rgba[][4], GLchan rgba[][4] )
2633 {
2634 const GLuint mask = TEXTURE0_ANY << (texUnit * 4);
2635
2636 if (ctx->Texture._ReallyEnabled & mask) {
2637 const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit];
2638
2639 if (textureUnit->_Current) { /* XXX need this? */
2640 GLchan texel[PB_SIZE][4];
2641
2642 if (textureUnit->LodBias != 0.0F) {
2643 /* apply LOD bias, but don't clamp yet */
2644 GLuint i;
2645 for (i=0;i<n;i++) {
2646 lambda[i] += textureUnit->LodBias;
2647 }
2648 }
2649
2650 if (textureUnit->_Current->MinLod != -1000.0
2651 || textureUnit->_Current->MaxLod != 1000.0) {
2652 /* apply LOD clamping to lambda */
2653 const GLfloat min = textureUnit->_Current->MinLod;
2654 const GLfloat max = textureUnit->_Current->MaxLod;
2655 GLuint i;
2656 for (i=0;i<n;i++) {
2657 GLfloat l = lambda[i];
2658 lambda[i] = CLAMP(l, min, max);
2659 }
2660 }
2661
2662 /* Sample the texture. */
2663 if (textureUnit->_Current->CompareFlag) {
2664 /* depth texture */
2665 sample_depth_texture(ctx, textureUnit, n, s, t, r, texel);
2666 }
2667 else {
2668 /* color texture */
2669 SWRAST_CONTEXT(ctx)->TextureSample[texUnit]( ctx, texUnit,
2670 textureUnit->_Current,
2671 n, s, t, r,
2672 lambda, texel );
2673 }
2674 apply_texture( ctx, textureUnit, n, primary_rgba,
2675 (const GLchan (*)[4]) texel, rgba );
2676 }
2677 }
2678 }