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