2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
30 #include "texformat.h"
32 #include "s_context.h"
33 #include "s_texfilter.h"
37 * Constants for integer linear interpolation.
39 #define ILERP_SCALE 65536.0F
40 #define ILERP_SHIFT 16
44 * Linear interpolation macros
46 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
47 #define ILERP(IT, A, B) ( (A) + (((IT) * ((B) - (A))) >> ILERP_SHIFT) )
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
59 lerp_2d(GLfloat a
, GLfloat b
,
60 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
62 const GLfloat temp0
= LERP(a
, v00
, v10
);
63 const GLfloat temp1
= LERP(a
, v01
, v11
);
64 return LERP(b
, temp0
, temp1
);
69 * Do 2D/biliner interpolation of integer values.
73 ilerp_2d(GLint ia
, GLint ib
,
74 GLint v00
, GLint v10
, GLint v01
, GLint v11
)
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
);
84 * Do 3D/trilinear interpolation of float values.
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
)
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
);
103 * Do 3D/trilinear interpolation of integer values.
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
)
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
);
123 * Do linear interpolation of colors.
126 lerp_rgba(GLchan result
[4], GLfloat t
, const GLchan a
[4], const GLchan b
[4])
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);
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]);
151 * Do bilinear interpolation of colors.
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])
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);
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]);
181 * Do trilinear interpolation of colors.
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])
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
]);
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
);
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
]);
216 * Compute the remainder of a divided by b, but be careful with
217 * negative values so that GL_REPEAT mode works right.
220 repeat_remainder(GLint a
, GLint b
)
225 return (a
+ 1) % b
+ b
- 1;
230 * Used to compute texel locations for linear sampling.
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
236 * U = texcoord in [0, width]
237 * I0, I1 = two nearest texel indexes
239 #define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
241 switch (wrapMode) { \
243 U = S * SIZE - 0.5F; \
244 if (img->_IsPowerOfTwo) { \
245 I0 = IFLOOR(U) & (SIZE - 1); \
246 I1 = (I0 + 1) & (SIZE - 1); \
249 I0 = repeat_remainder(IFLOOR(U), SIZE); \
250 I1 = repeat_remainder(I0 + 1, SIZE); \
253 case GL_CLAMP_TO_EDGE: \
256 else if (S >= 1.0F) \
257 U = (GLfloat) SIZE; \
265 if (I1 >= (GLint) SIZE) \
268 case GL_CLAMP_TO_BORDER: \
270 const GLfloat min = -1.0F / (2.0F * SIZE); \
271 const GLfloat max = 1.0F - min; \
283 case GL_MIRRORED_REPEAT: \
285 const GLint flr = IFLOOR(S); \
287 U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
289 U = S - (GLfloat) flr; /* flr is even */ \
290 U = (U * SIZE) - 0.5F; \
295 if (I1 >= (GLint) SIZE) \
299 case GL_MIRROR_CLAMP_EXT: \
302 U = (GLfloat) SIZE; \
309 case GL_MIRROR_CLAMP_TO_EDGE_EXT: \
312 U = (GLfloat) SIZE; \
320 if (I1 >= (GLint) SIZE) \
323 case GL_MIRROR_CLAMP_TO_BORDER_EXT: \
325 const GLfloat min = -1.0F / (2.0F * SIZE); \
326 const GLfloat max = 1.0F - min; \
342 else if (S >= 1.0F) \
343 U = (GLfloat) SIZE; \
351 _mesa_problem(ctx, "Bad wrap mode"); \
357 * Used to compute texel location for nearest sampling.
359 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
361 switch (wrapMode) { \
363 /* s limited to [0,1) */ \
364 /* i limited to [0,size-1] */ \
365 I = IFLOOR(S * SIZE); \
366 if (img->_IsPowerOfTwo) \
369 I = repeat_remainder(I, SIZE); \
371 case GL_CLAMP_TO_EDGE: \
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; \
382 I = IFLOOR(S * SIZE); \
385 case GL_CLAMP_TO_BORDER: \
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; \
396 I = IFLOOR(S * SIZE); \
399 case GL_MIRRORED_REPEAT: \
401 const GLfloat min = 1.0F / (2.0F * SIZE); \
402 const GLfloat max = 1.0F - min; \
403 const GLint flr = IFLOOR(S); \
406 u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
408 u = S - (GLfloat) flr; /* flr is even */ \
414 I = IFLOOR(u * SIZE); \
417 case GL_MIRROR_CLAMP_EXT: \
419 /* s limited to [0,1] */ \
420 /* i limited to [0,size-1] */ \
421 const GLfloat u = FABSF(S); \
424 else if (u >= 1.0F) \
427 I = IFLOOR(u * SIZE); \
430 case GL_MIRROR_CLAMP_TO_EDGE_EXT: \
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); \
442 I = IFLOOR(u * SIZE); \
445 case GL_MIRROR_CLAMP_TO_BORDER_EXT: \
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); \
457 I = IFLOOR(u * SIZE); \
461 /* s limited to [0,1] */ \
462 /* i limited to [0,size-1] */ \
465 else if (S >= 1.0F) \
468 I = IFLOOR(S * SIZE); \
471 _mesa_problem(ctx, "Bad wrap mode"); \
476 /* Power of two image sizes only */
477 #define COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(S, U, SIZE, I0, I1) \
479 U = S * SIZE - 0.5F; \
480 I0 = IFLOOR(U) & (SIZE - 1); \
481 I1 = (I0 + 1) & (SIZE - 1); \
486 * For linear interpolation between mipmap levels N and N+1, this function
490 linear_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
493 return tObj
->BaseLevel
;
494 else if (lambda
> tObj
->_MaxLambda
)
495 return (GLint
) (tObj
->BaseLevel
+ tObj
->_MaxLambda
);
497 return (GLint
) (tObj
->BaseLevel
+ lambda
);
502 * Compute the nearest mipmap level to take texels from.
505 nearest_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
511 else if (lambda
> tObj
->_MaxLambda
+ 0.4999F
)
512 l
= tObj
->_MaxLambda
+ 0.4999F
;
515 level
= (GLint
) (tObj
->BaseLevel
+ l
+ 0.5F
);
516 if (level
> tObj
->_MaxLevel
)
517 level
= tObj
->_MaxLevel
;
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).
530 #define FRAC(f) ((f) - IFLOOR(f))
535 * Bitflags for texture border color sampling.
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.
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
)
557 GLfloat minMagThresh
;
559 /* we shouldn't be here if minfilter == magfilter */
560 ASSERT(tObj
->MinFilter
!= tObj
->MagFilter
);
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
)) {
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.
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));
585 else { /* increasing */
586 for (i
= 0; i
< n
- 1; i
++) {
587 ASSERT((GLint
) (lambda
[i
] * 10) <= (GLint
) (lambda
[i
+1] * 10));
593 if (lambda
[0] <= minMagThresh
&& (n
<= 1 || lambda
[n
-1] <= minMagThresh
)) {
594 /* magnification for whole span */
597 *minStart
= *minEnd
= 0;
599 else if (lambda
[0] > minMagThresh
&& (n
<=1 || lambda
[n
-1] > minMagThresh
)) {
600 /* minification for whole span */
603 *magStart
= *magEnd
= 0;
606 /* a mix of minification and magnification */
608 if (lambda
[0] > minMagThresh
) {
609 /* start with minification */
610 for (i
= 1; i
< n
; i
++) {
611 if (lambda
[i
] <= minMagThresh
)
620 /* start with magnification */
621 for (i
= 1; i
< n
; i
++) {
622 if (lambda
[i
] > minMagThresh
)
633 /* Verify the min/mag Start/End values
634 * We don't use this either (see above)
638 for (i
= 0; i
< n
; i
++) {
639 if (lambda
[i
] > minMagThresh
) {
641 ASSERT(i
>= *minStart
);
646 ASSERT(i
>= *magStart
);
655 /**********************************************************************/
656 /* 1-D Texture Sampling Functions */
657 /**********************************************************************/
660 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
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])
668 const GLint width
= img
->Width2
; /* without border, power of two */
670 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
671 /* skip over the border, if any */
673 if (i
< 0 || i
>= (GLint
) img
->Width
) {
674 /* Need this test for GL_CLAMP_TO_BORDER mode */
675 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
678 img
->FetchTexelc(img
, i
, 0, 0, rgba
);
684 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
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])
692 const GLint width
= img
->Width2
;
695 GLbitfield useBorderColor
= 0x0;
697 GLchan t0
[4], t1
[4]; /* texels */
699 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
706 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
707 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
710 /* fetch texel colors */
711 if (useBorderColor
& I0BIT
) {
712 COPY_CHAN4(t0
, tObj
->_BorderChan
);
715 img
->FetchTexelc(img
, i0
, 0, 0, t0
);
717 if (useBorderColor
& I1BIT
) {
718 COPY_CHAN4(t1
, tObj
->_BorderChan
);
721 img
->FetchTexelc(img
, i1
, 0, 0, t1
);
725 lerp_rgba(rgba
, a
, t0
, t1
);
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])
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
]);
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])
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
]);
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])
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
]);
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
);
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])
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
]);
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
);
812 sample_nearest_1d( GLcontext
*ctx
,
813 const struct gl_texture_object
*tObj
, GLuint n
,
814 const GLfloat texcoords
[][4], const GLfloat lambda
[],
818 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
821 sample_1d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
828 sample_linear_1d( GLcontext
*ctx
,
829 const struct gl_texture_object
*tObj
, GLuint n
,
830 const GLfloat texcoords
[][4], const GLfloat lambda
[],
834 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
837 sample_1d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
843 * Given an (s) texture coordinate and lambda (level of detail) value,
844 * return a texture sample.
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] )
853 GLuint minStart
, minEnd
; /* texels with minification */
854 GLuint magStart
, magEnd
; /* texels with magnification */
857 ASSERT(lambda
!= NULL
);
858 compute_min_mag_ranges(tObj
, n
, lambda
,
859 &minStart
, &minEnd
, &magStart
, &magEnd
);
861 if (minStart
< minEnd
) {
862 /* do the minified texels */
863 const GLuint m
= minEnd
- minStart
;
864 switch (tObj
->MinFilter
) {
866 for (i
= minStart
; i
< minEnd
; i
++)
867 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
868 texcoords
[i
], rgba
[i
]);
871 for (i
= minStart
; i
< minEnd
; i
++)
872 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
873 texcoords
[i
], rgba
[i
]);
875 case GL_NEAREST_MIPMAP_NEAREST
:
876 sample_1d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
877 lambda
+ minStart
, rgba
+ minStart
);
879 case GL_LINEAR_MIPMAP_NEAREST
:
880 sample_1d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
881 lambda
+ minStart
, rgba
+ minStart
);
883 case GL_NEAREST_MIPMAP_LINEAR
:
884 sample_1d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
885 lambda
+ minStart
, rgba
+ minStart
);
887 case GL_LINEAR_MIPMAP_LINEAR
:
888 sample_1d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
889 lambda
+ minStart
, rgba
+ minStart
);
892 _mesa_problem(ctx
, "Bad min filter in sample_1d_texture");
897 if (magStart
< magEnd
) {
898 /* do the magnified texels */
899 switch (tObj
->MagFilter
) {
901 for (i
= magStart
; i
< magEnd
; i
++)
902 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
903 texcoords
[i
], rgba
[i
]);
906 for (i
= magStart
; i
< magEnd
; i
++)
907 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
908 texcoords
[i
], rgba
[i
]);
911 _mesa_problem(ctx
, "Bad mag filter in sample_1d_texture");
918 /**********************************************************************/
919 /* 2-D Texture Sampling Functions */
920 /**********************************************************************/
924 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
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],
933 const GLint width
= img
->Width2
; /* without border, power of two */
934 const GLint height
= img
->Height2
; /* without border, power of two */
938 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
939 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
941 /* skip over the border, if any */
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
);
950 img
->FetchTexelc(img
, i
, j
, 0, rgba
);
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>.
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],
967 const GLint width
= img
->Width2
;
968 const GLint height
= img
->Height2
;
969 GLint i0
, j0
, i1
, j1
;
970 GLbitfield useBorderColor
= 0x0;
973 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
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
);
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
;
991 /* fetch four texel colors */
992 if (useBorderColor
& (I0BIT
| J0BIT
)) {
993 COPY_CHAN4(t00
, tObj
->_BorderChan
);
996 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
998 if (useBorderColor
& (I1BIT
| J0BIT
)) {
999 COPY_CHAN4(t10
, tObj
->_BorderChan
);
1002 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
1004 if (useBorderColor
& (I0BIT
| J1BIT
)) {
1005 COPY_CHAN4(t01
, tObj
->_BorderChan
);
1008 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1010 if (useBorderColor
& (I1BIT
| J1BIT
)) {
1011 COPY_CHAN4(t11
, tObj
->_BorderChan
);
1014 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1019 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1024 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1025 * We don't have to worry about the texture border.
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],
1034 const GLint width
= img
->Width2
;
1035 const GLint height
= img
->Height2
;
1036 GLint i0
, j0
, i1
, j1
;
1039 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
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
);
1049 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[0], u
, width
, i0
, i1
);
1050 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[1], v
, height
, j0
, j1
);
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
);
1059 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
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])
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
]);
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])
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
]);
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])
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
]);
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
);
1121 /* Trilinear filtering */
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] )
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
]);
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
);
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] )
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
]);
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
);
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] )
1181 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1184 sample_2d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
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] )
1197 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1199 if (tObj
->WrapS
== GL_REPEAT
&&
1200 tObj
->WrapT
== GL_REPEAT
&&
1201 image
->_IsPowerOfTwo
) {
1203 sample_2d_linear_repeat(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1208 sample_2d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1215 * Optimized 2-D texture sampling:
1216 * S and T wrap mode == GL_REPEAT
1217 * GL_NEAREST min/mag filter
1219 * RowStride == Width,
1223 opt_sample_rgb_2d( GLcontext
*ctx
,
1224 const struct gl_texture_object
*tObj
,
1225 GLuint n
, const GLfloat texcoords
[][4],
1226 const GLfloat lambda
[], GLchan rgba
[][4] )
1228 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1229 const GLfloat width
= (GLfloat
) img
->Width
;
1230 const GLfloat height
= (GLfloat
) img
->Height
;
1231 const GLint colMask
= img
->Width
- 1;
1232 const GLint rowMask
= img
->Height
- 1;
1233 const GLint shift
= img
->WidthLog2
;
1237 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1238 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1239 ASSERT(img
->Border
==0);
1240 ASSERT(img
->_BaseFormat
==GL_RGB
);
1241 ASSERT(img
->_IsPowerOfTwo
);
1243 for (k
=0; k
<n
; k
++) {
1244 GLint i
= IFLOOR(texcoords
[k
][0] * width
) & colMask
;
1245 GLint j
= IFLOOR(texcoords
[k
][1] * height
) & rowMask
;
1246 GLint pos
= (j
<< shift
) | i
;
1247 GLchan
*texel
= ((GLchan
*) img
->Data
) + 3*pos
;
1248 rgba
[k
][RCOMP
] = texel
[0];
1249 rgba
[k
][GCOMP
] = texel
[1];
1250 rgba
[k
][BCOMP
] = texel
[2];
1256 * Optimized 2-D texture sampling:
1257 * S and T wrap mode == GL_REPEAT
1258 * GL_NEAREST min/mag filter
1260 * RowStride == Width,
1264 opt_sample_rgba_2d( GLcontext
*ctx
,
1265 const struct gl_texture_object
*tObj
,
1266 GLuint n
, const GLfloat texcoords
[][4],
1267 const GLfloat lambda
[], GLchan rgba
[][4] )
1269 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1270 const GLfloat width
= (GLfloat
) img
->Width
;
1271 const GLfloat height
= (GLfloat
) img
->Height
;
1272 const GLint colMask
= img
->Width
- 1;
1273 const GLint rowMask
= img
->Height
- 1;
1274 const GLint shift
= img
->WidthLog2
;
1278 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1279 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1280 ASSERT(img
->Border
==0);
1281 ASSERT(img
->_BaseFormat
==GL_RGBA
);
1282 ASSERT(img
->_IsPowerOfTwo
);
1284 for (i
= 0; i
< n
; i
++) {
1285 const GLint col
= IFLOOR(texcoords
[i
][0] * width
) & colMask
;
1286 const GLint row
= IFLOOR(texcoords
[i
][1] * height
) & rowMask
;
1287 const GLint pos
= (row
<< shift
) | col
;
1288 const GLchan
*texel
= ((GLchan
*) img
->Data
) + (pos
<< 2); /* pos*4 */
1289 COPY_CHAN4(rgba
[i
], texel
);
1295 * Given an array of texture coordinate and lambda (level of detail)
1296 * values, return an array of texture sample.
1299 sample_lambda_2d( GLcontext
*ctx
,
1300 const struct gl_texture_object
*tObj
,
1301 GLuint n
, const GLfloat texcoords
[][4],
1302 const GLfloat lambda
[], GLchan rgba
[][4] )
1304 const struct gl_texture_image
*tImg
= tObj
->Image
[0][tObj
->BaseLevel
];
1305 GLuint minStart
, minEnd
; /* texels with minification */
1306 GLuint magStart
, magEnd
; /* texels with magnification */
1308 const GLboolean repeatNoBorderPOT
= (tObj
->WrapS
== GL_REPEAT
)
1309 && (tObj
->WrapT
== GL_REPEAT
)
1310 && (tImg
->Border
== 0 && (tImg
->Width
== tImg
->RowStride
))
1311 && (tImg
->_BaseFormat
!= GL_COLOR_INDEX
)
1312 && tImg
->_IsPowerOfTwo
;
1314 ASSERT(lambda
!= NULL
);
1315 compute_min_mag_ranges(tObj
, n
, lambda
,
1316 &minStart
, &minEnd
, &magStart
, &magEnd
);
1318 if (minStart
< minEnd
) {
1319 /* do the minified texels */
1320 const GLuint m
= minEnd
- minStart
;
1321 switch (tObj
->MinFilter
) {
1323 if (repeatNoBorderPOT
) {
1324 switch (tImg
->TexFormat
->MesaFormat
) {
1325 case MESA_FORMAT_RGB
:
1326 case MESA_FORMAT_RGB888
:
1327 /*case MESA_FORMAT_BGR888:*/
1328 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1329 NULL
, rgba
+ minStart
);
1331 case MESA_FORMAT_RGBA
:
1332 case MESA_FORMAT_RGBA8888
:
1333 case MESA_FORMAT_ARGB8888
:
1334 /*case MESA_FORMAT_ABGR8888:*/
1335 /*case MESA_FORMAT_BGRA8888:*/
1336 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1337 NULL
, rgba
+ minStart
);
1340 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1341 NULL
, rgba
+ minStart
);
1345 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1346 NULL
, rgba
+ minStart
);
1350 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1351 NULL
, rgba
+ minStart
);
1353 case GL_NEAREST_MIPMAP_NEAREST
:
1354 sample_2d_nearest_mipmap_nearest(ctx
, tObj
, m
,
1355 texcoords
+ minStart
,
1356 lambda
+ minStart
, rgba
+ minStart
);
1358 case GL_LINEAR_MIPMAP_NEAREST
:
1359 sample_2d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1360 lambda
+ minStart
, rgba
+ minStart
);
1362 case GL_NEAREST_MIPMAP_LINEAR
:
1363 sample_2d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1364 lambda
+ minStart
, rgba
+ minStart
);
1366 case GL_LINEAR_MIPMAP_LINEAR
:
1367 if (repeatNoBorderPOT
)
1368 sample_2d_linear_mipmap_linear_repeat(ctx
, tObj
, m
,
1369 texcoords
+ minStart
, lambda
+ minStart
, rgba
+ minStart
);
1371 sample_2d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1372 lambda
+ minStart
, rgba
+ minStart
);
1375 _mesa_problem(ctx
, "Bad min filter in sample_2d_texture");
1380 if (magStart
< magEnd
) {
1381 /* do the magnified texels */
1382 const GLuint m
= magEnd
- magStart
;
1384 switch (tObj
->MagFilter
) {
1386 if (repeatNoBorderPOT
) {
1387 switch (tImg
->TexFormat
->MesaFormat
) {
1388 case MESA_FORMAT_RGB
:
1389 case MESA_FORMAT_RGB888
:
1390 /*case MESA_FORMAT_BGR888:*/
1391 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1392 NULL
, rgba
+ magStart
);
1394 case MESA_FORMAT_RGBA
:
1395 case MESA_FORMAT_RGBA8888
:
1396 case MESA_FORMAT_ARGB8888
:
1397 /*case MESA_FORMAT_ABGR8888:*/
1398 /*case MESA_FORMAT_BGRA8888:*/
1399 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1400 NULL
, rgba
+ magStart
);
1403 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1404 NULL
, rgba
+ magStart
);
1408 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1409 NULL
, rgba
+ magStart
);
1413 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1414 NULL
, rgba
+ magStart
);
1417 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_2d");
1424 /**********************************************************************/
1425 /* 3-D Texture Sampling Functions */
1426 /**********************************************************************/
1429 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1432 sample_3d_nearest(GLcontext
*ctx
,
1433 const struct gl_texture_object
*tObj
,
1434 const struct gl_texture_image
*img
,
1435 const GLfloat texcoord
[4],
1438 const GLint width
= img
->Width2
; /* without border, power of two */
1439 const GLint height
= img
->Height2
; /* without border, power of two */
1440 const GLint depth
= img
->Depth2
; /* without border, power of two */
1444 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
1445 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
1446 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapR
, texcoord
[2], depth
, k
);
1448 if (i
< 0 || i
>= (GLint
) img
->Width
||
1449 j
< 0 || j
>= (GLint
) img
->Height
||
1450 k
< 0 || k
>= (GLint
) img
->Depth
) {
1451 /* Need this test for GL_CLAMP_TO_BORDER mode */
1452 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
1455 img
->FetchTexelc(img
, i
, j
, k
, rgba
);
1462 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1465 sample_3d_linear(GLcontext
*ctx
,
1466 const struct gl_texture_object
*tObj
,
1467 const struct gl_texture_image
*img
,
1468 const GLfloat texcoord
[4],
1471 const GLint width
= img
->Width2
;
1472 const GLint height
= img
->Height2
;
1473 const GLint depth
= img
->Depth2
;
1474 GLint i0
, j0
, k0
, i1
, j1
, k1
;
1475 GLbitfield useBorderColor
= 0x0;
1478 GLchan t000
[4], t010
[4], t001
[4], t011
[4];
1479 GLchan t100
[4], t110
[4], t101
[4], t111
[4];
1481 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
1482 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
1483 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapR
, texcoord
[2], w
, depth
, k0
, k1
);
1494 /* check if sampling texture border color */
1495 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1496 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1497 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1498 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1499 if (k0
< 0 || k0
>= depth
) useBorderColor
|= K0BIT
;
1500 if (k1
< 0 || k1
>= depth
) useBorderColor
|= K1BIT
;
1504 if (useBorderColor
& (I0BIT
| J0BIT
| K0BIT
)) {
1505 COPY_CHAN4(t000
, tObj
->_BorderChan
);
1508 img
->FetchTexelc(img
, i0
, j0
, k0
, t000
);
1510 if (useBorderColor
& (I1BIT
| J0BIT
| K0BIT
)) {
1511 COPY_CHAN4(t100
, tObj
->_BorderChan
);
1514 img
->FetchTexelc(img
, i1
, j0
, k0
, t100
);
1516 if (useBorderColor
& (I0BIT
| J1BIT
| K0BIT
)) {
1517 COPY_CHAN4(t010
, tObj
->_BorderChan
);
1520 img
->FetchTexelc(img
, i0
, j1
, k0
, t010
);
1522 if (useBorderColor
& (I1BIT
| J1BIT
| K0BIT
)) {
1523 COPY_CHAN4(t110
, tObj
->_BorderChan
);
1526 img
->FetchTexelc(img
, i1
, j1
, k0
, t110
);
1529 if (useBorderColor
& (I0BIT
| J0BIT
| K1BIT
)) {
1530 COPY_CHAN4(t001
, tObj
->_BorderChan
);
1533 img
->FetchTexelc(img
, i0
, j0
, k1
, t001
);
1535 if (useBorderColor
& (I1BIT
| J0BIT
| K1BIT
)) {
1536 COPY_CHAN4(t101
, tObj
->_BorderChan
);
1539 img
->FetchTexelc(img
, i1
, j0
, k1
, t101
);
1541 if (useBorderColor
& (I0BIT
| J1BIT
| K1BIT
)) {
1542 COPY_CHAN4(t011
, tObj
->_BorderChan
);
1545 img
->FetchTexelc(img
, i0
, j1
, k1
, t011
);
1547 if (useBorderColor
& (I1BIT
| J1BIT
| K1BIT
)) {
1548 COPY_CHAN4(t111
, tObj
->_BorderChan
);
1551 img
->FetchTexelc(img
, i1
, j1
, k1
, t111
);
1554 /* trilinear interpolation of samples */
1558 lerp_rgba_3d(rgba
, a
, b
, c
, t000
, t100
, t010
, t110
, t001
, t101
, t011
, t111
);
1564 sample_3d_nearest_mipmap_nearest(GLcontext
*ctx
,
1565 const struct gl_texture_object
*tObj
,
1566 GLuint n
, const GLfloat texcoord
[][4],
1567 const GLfloat lambda
[], GLchan rgba
[][4] )
1570 for (i
= 0; i
< n
; i
++) {
1571 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1572 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1578 sample_3d_linear_mipmap_nearest(GLcontext
*ctx
,
1579 const struct gl_texture_object
*tObj
,
1580 GLuint n
, const GLfloat texcoord
[][4],
1581 const GLfloat lambda
[], GLchan rgba
[][4])
1584 ASSERT(lambda
!= NULL
);
1585 for (i
= 0; i
< n
; i
++) {
1586 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1587 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1593 sample_3d_nearest_mipmap_linear(GLcontext
*ctx
,
1594 const struct gl_texture_object
*tObj
,
1595 GLuint n
, const GLfloat texcoord
[][4],
1596 const GLfloat lambda
[], GLchan rgba
[][4])
1599 ASSERT(lambda
!= NULL
);
1600 for (i
= 0; i
< n
; i
++) {
1601 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1602 if (level
>= tObj
->_MaxLevel
) {
1603 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1604 texcoord
[i
], rgba
[i
]);
1607 GLchan t0
[4], t1
[4]; /* texels */
1608 const GLfloat f
= FRAC(lambda
[i
]);
1609 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1610 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1611 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1618 sample_3d_linear_mipmap_linear(GLcontext
*ctx
,
1619 const struct gl_texture_object
*tObj
,
1620 GLuint n
, const GLfloat texcoord
[][4],
1621 const GLfloat lambda
[], GLchan rgba
[][4])
1624 ASSERT(lambda
!= NULL
);
1625 for (i
= 0; i
< n
; i
++) {
1626 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1627 if (level
>= tObj
->_MaxLevel
) {
1628 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1629 texcoord
[i
], rgba
[i
]);
1632 GLchan t0
[4], t1
[4]; /* texels */
1633 const GLfloat f
= FRAC(lambda
[i
]);
1634 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1635 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1636 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1643 sample_nearest_3d(GLcontext
*ctx
,
1644 const struct gl_texture_object
*tObj
, GLuint n
,
1645 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1649 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1652 sample_3d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1659 sample_linear_3d( GLcontext
*ctx
,
1660 const struct gl_texture_object
*tObj
, GLuint n
,
1661 const GLfloat texcoords
[][4],
1662 const GLfloat lambda
[], GLchan rgba
[][4] )
1665 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1668 sample_3d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1674 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1675 * return a texture sample.
1678 sample_lambda_3d( GLcontext
*ctx
,
1679 const struct gl_texture_object
*tObj
, GLuint n
,
1680 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1683 GLuint minStart
, minEnd
; /* texels with minification */
1684 GLuint magStart
, magEnd
; /* texels with magnification */
1687 ASSERT(lambda
!= NULL
);
1688 compute_min_mag_ranges(tObj
, n
, lambda
,
1689 &minStart
, &minEnd
, &magStart
, &magEnd
);
1691 if (minStart
< minEnd
) {
1692 /* do the minified texels */
1693 GLuint m
= minEnd
- minStart
;
1694 switch (tObj
->MinFilter
) {
1696 for (i
= minStart
; i
< minEnd
; i
++)
1697 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1698 texcoords
[i
], rgba
[i
]);
1701 for (i
= minStart
; i
< minEnd
; i
++)
1702 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1703 texcoords
[i
], rgba
[i
]);
1705 case GL_NEAREST_MIPMAP_NEAREST
:
1706 sample_3d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1707 lambda
+ minStart
, rgba
+ minStart
);
1709 case GL_LINEAR_MIPMAP_NEAREST
:
1710 sample_3d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1711 lambda
+ minStart
, rgba
+ minStart
);
1713 case GL_NEAREST_MIPMAP_LINEAR
:
1714 sample_3d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1715 lambda
+ minStart
, rgba
+ minStart
);
1717 case GL_LINEAR_MIPMAP_LINEAR
:
1718 sample_3d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1719 lambda
+ minStart
, rgba
+ minStart
);
1722 _mesa_problem(ctx
, "Bad min filter in sample_3d_texture");
1727 if (magStart
< magEnd
) {
1728 /* do the magnified texels */
1729 switch (tObj
->MagFilter
) {
1731 for (i
= magStart
; i
< magEnd
; i
++)
1732 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1733 texcoords
[i
], rgba
[i
]);
1736 for (i
= magStart
; i
< magEnd
; i
++)
1737 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1738 texcoords
[i
], rgba
[i
]);
1741 _mesa_problem(ctx
, "Bad mag filter in sample_3d_texture");
1748 /**********************************************************************/
1749 /* Texture Cube Map Sampling Functions */
1750 /**********************************************************************/
1753 * Choose one of six sides of a texture cube map given the texture
1754 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1757 static const struct gl_texture_image
**
1758 choose_cube_face(const struct gl_texture_object
*texObj
,
1759 const GLfloat texcoord
[4], GLfloat newCoord
[4])
1763 direction target sc tc ma
1764 ---------- ------------------------------- --- --- ---
1765 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1766 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1767 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1768 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1769 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1770 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1772 const GLfloat rx
= texcoord
[0];
1773 const GLfloat ry
= texcoord
[1];
1774 const GLfloat rz
= texcoord
[2];
1775 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
1779 if (arx
> ary
&& arx
> arz
) {
1793 else if (ary
> arx
&& ary
> arz
) {
1822 newCoord
[0] = ( sc
/ ma
+ 1.0F
) * 0.5F
;
1823 newCoord
[1] = ( tc
/ ma
+ 1.0F
) * 0.5F
;
1824 return (const struct gl_texture_image
**) texObj
->Image
[face
];
1829 sample_nearest_cube(GLcontext
*ctx
,
1830 const struct gl_texture_object
*tObj
, GLuint n
,
1831 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1836 for (i
= 0; i
< n
; i
++) {
1837 const struct gl_texture_image
**images
;
1838 GLfloat newCoord
[4];
1839 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1840 sample_2d_nearest(ctx
, tObj
, images
[tObj
->BaseLevel
],
1847 sample_linear_cube(GLcontext
*ctx
,
1848 const struct gl_texture_object
*tObj
, GLuint n
,
1849 const GLfloat texcoords
[][4],
1850 const GLfloat lambda
[], GLchan rgba
[][4])
1854 for (i
= 0; i
< n
; i
++) {
1855 const struct gl_texture_image
**images
;
1856 GLfloat newCoord
[4];
1857 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1858 sample_2d_linear(ctx
, tObj
, images
[tObj
->BaseLevel
],
1865 sample_cube_nearest_mipmap_nearest(GLcontext
*ctx
,
1866 const struct gl_texture_object
*tObj
,
1867 GLuint n
, const GLfloat texcoord
[][4],
1868 const GLfloat lambda
[], GLchan rgba
[][4])
1871 ASSERT(lambda
!= NULL
);
1872 for (i
= 0; i
< n
; i
++) {
1873 const struct gl_texture_image
**images
;
1874 GLfloat newCoord
[4];
1875 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1876 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1877 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1883 sample_cube_linear_mipmap_nearest(GLcontext
*ctx
,
1884 const struct gl_texture_object
*tObj
,
1885 GLuint n
, const GLfloat texcoord
[][4],
1886 const GLfloat lambda
[], GLchan rgba
[][4])
1889 ASSERT(lambda
!= NULL
);
1890 for (i
= 0; i
< n
; i
++) {
1891 const struct gl_texture_image
**images
;
1892 GLfloat newCoord
[4];
1893 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1894 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1895 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1901 sample_cube_nearest_mipmap_linear(GLcontext
*ctx
,
1902 const struct gl_texture_object
*tObj
,
1903 GLuint n
, const GLfloat texcoord
[][4],
1904 const GLfloat lambda
[], GLchan rgba
[][4])
1907 ASSERT(lambda
!= NULL
);
1908 for (i
= 0; i
< n
; i
++) {
1909 const struct gl_texture_image
**images
;
1910 GLfloat newCoord
[4];
1911 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1912 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1913 if (level
>= tObj
->_MaxLevel
) {
1914 sample_2d_nearest(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1918 GLchan t0
[4], t1
[4]; /* texels */
1919 const GLfloat f
= FRAC(lambda
[i
]);
1920 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, t0
);
1921 sample_2d_nearest(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1922 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1929 sample_cube_linear_mipmap_linear(GLcontext
*ctx
,
1930 const struct gl_texture_object
*tObj
,
1931 GLuint n
, const GLfloat texcoord
[][4],
1932 const GLfloat lambda
[], GLchan rgba
[][4])
1935 ASSERT(lambda
!= NULL
);
1936 for (i
= 0; i
< n
; i
++) {
1937 const struct gl_texture_image
**images
;
1938 GLfloat newCoord
[4];
1939 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1940 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1941 if (level
>= tObj
->_MaxLevel
) {
1942 sample_2d_linear(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1946 GLchan t0
[4], t1
[4];
1947 const GLfloat f
= FRAC(lambda
[i
]);
1948 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, t0
);
1949 sample_2d_linear(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1950 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1957 sample_lambda_cube( GLcontext
*ctx
,
1958 const struct gl_texture_object
*tObj
, GLuint n
,
1959 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1962 GLuint minStart
, minEnd
; /* texels with minification */
1963 GLuint magStart
, magEnd
; /* texels with magnification */
1965 ASSERT(lambda
!= NULL
);
1966 compute_min_mag_ranges(tObj
, n
, lambda
,
1967 &minStart
, &minEnd
, &magStart
, &magEnd
);
1969 if (minStart
< minEnd
) {
1970 /* do the minified texels */
1971 const GLuint m
= minEnd
- minStart
;
1972 switch (tObj
->MinFilter
) {
1974 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1975 lambda
+ minStart
, rgba
+ minStart
);
1978 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1979 lambda
+ minStart
, rgba
+ minStart
);
1981 case GL_NEAREST_MIPMAP_NEAREST
:
1982 sample_cube_nearest_mipmap_nearest(ctx
, tObj
, m
,
1983 texcoords
+ minStart
,
1984 lambda
+ minStart
, rgba
+ minStart
);
1986 case GL_LINEAR_MIPMAP_NEAREST
:
1987 sample_cube_linear_mipmap_nearest(ctx
, tObj
, m
,
1988 texcoords
+ minStart
,
1989 lambda
+ minStart
, rgba
+ minStart
);
1991 case GL_NEAREST_MIPMAP_LINEAR
:
1992 sample_cube_nearest_mipmap_linear(ctx
, tObj
, m
,
1993 texcoords
+ minStart
,
1994 lambda
+ minStart
, rgba
+ minStart
);
1996 case GL_LINEAR_MIPMAP_LINEAR
:
1997 sample_cube_linear_mipmap_linear(ctx
, tObj
, m
,
1998 texcoords
+ minStart
,
1999 lambda
+ minStart
, rgba
+ minStart
);
2002 _mesa_problem(ctx
, "Bad min filter in sample_lambda_cube");
2006 if (magStart
< magEnd
) {
2007 /* do the magnified texels */
2008 const GLuint m
= magEnd
- magStart
;
2009 switch (tObj
->MagFilter
) {
2011 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2012 lambda
+ magStart
, rgba
+ magStart
);
2015 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2016 lambda
+ magStart
, rgba
+ magStart
);
2019 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_cube");
2025 /**********************************************************************/
2026 /* Texture Rectangle Sampling Functions */
2027 /**********************************************************************/
2030 sample_nearest_rect(GLcontext
*ctx
,
2031 const struct gl_texture_object
*tObj
, GLuint n
,
2032 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2035 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2036 const GLfloat width
= (GLfloat
) img
->Width
;
2037 const GLfloat height
= (GLfloat
) img
->Height
;
2038 const GLint width_minus_1
= img
->Width
- 1;
2039 const GLint height_minus_1
= img
->Height
- 1;
2045 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2046 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2047 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2048 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2049 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2050 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2051 ASSERT(img
->_BaseFormat
!= GL_COLOR_INDEX
);
2053 /* XXX move Wrap mode tests outside of loops for common cases */
2054 for (i
= 0; i
< n
; i
++) {
2056 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2057 if (tObj
->WrapS
== GL_CLAMP
) {
2058 col
= IFLOOR( CLAMP(texcoords
[i
][0], 0.0F
, width
- 1) );
2060 else if (tObj
->WrapS
== GL_CLAMP_TO_EDGE
) {
2061 col
= IFLOOR( CLAMP(texcoords
[i
][0], 0.5F
, width
- 0.5F
) );
2064 col
= IFLOOR( CLAMP(texcoords
[i
][0], -0.5F
, width
+ 0.5F
) );
2066 if (tObj
->WrapT
== GL_CLAMP
) {
2067 row
= IFLOOR( CLAMP(texcoords
[i
][1], 0.0F
, height
- 1) );
2069 else if (tObj
->WrapT
== GL_CLAMP_TO_EDGE
) {
2070 row
= IFLOOR( CLAMP(texcoords
[i
][1], 0.5F
, height
- 0.5F
) );
2073 row
= IFLOOR( CLAMP(texcoords
[i
][1], -0.5F
, height
+ 0.5F
) );
2076 if (col
< 0 || col
> width_minus_1
|| row
< 0 || row
> height_minus_1
)
2077 COPY_CHAN4(rgba
[i
], tObj
->_BorderChan
);
2079 img
->FetchTexelc(img
, col
, row
, 0, rgba
[i
]);
2085 sample_linear_rect(GLcontext
*ctx
,
2086 const struct gl_texture_object
*tObj
, GLuint n
,
2087 const GLfloat texcoords
[][4],
2088 const GLfloat lambda
[], GLchan rgba
[][4])
2090 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2091 const GLfloat width
= (GLfloat
) img
->Width
;
2092 const GLfloat height
= (GLfloat
) img
->Height
;
2093 const GLint width_minus_1
= img
->Width
- 1;
2094 const GLint height_minus_1
= img
->Height
- 1;
2100 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2101 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2102 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2103 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2104 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2105 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2106 ASSERT(img
->_BaseFormat
!= GL_COLOR_INDEX
);
2108 /* XXX lots of opportunity for optimization in this loop */
2109 for (i
= 0; i
< n
; i
++) {
2111 GLint i0
, j0
, i1
, j1
;
2112 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2114 GLbitfield useBorderColor
= 0x0;
2116 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2117 if (tObj
->WrapS
== GL_CLAMP
) {
2118 /* Not exactly what the spec says, but it matches NVIDIA output */
2119 fcol
= CLAMP(texcoords
[i
][0] - 0.5F
, 0.0, width_minus_1
);
2123 else if (tObj
->WrapS
== GL_CLAMP_TO_EDGE
) {
2124 fcol
= CLAMP(texcoords
[i
][0], 0.5F
, width
- 0.5F
);
2128 if (i1
> width_minus_1
)
2132 ASSERT(tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2133 fcol
= CLAMP(texcoords
[i
][0], -0.5F
, width
+ 0.5F
);
2139 if (tObj
->WrapT
== GL_CLAMP
) {
2140 /* Not exactly what the spec says, but it matches NVIDIA output */
2141 frow
= CLAMP(texcoords
[i
][1] - 0.5F
, 0.0, width_minus_1
);
2145 else if (tObj
->WrapT
== GL_CLAMP_TO_EDGE
) {
2146 frow
= CLAMP(texcoords
[i
][1], 0.5F
, height
- 0.5F
);
2150 if (j1
> height_minus_1
)
2151 j1
= height_minus_1
;
2154 ASSERT(tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2155 frow
= CLAMP(texcoords
[i
][1], -0.5F
, height
+ 0.5F
);
2161 /* compute integer rows/columns */
2162 if (i0
< 0 || i0
> width_minus_1
) useBorderColor
|= I0BIT
;
2163 if (i1
< 0 || i1
> width_minus_1
) useBorderColor
|= I1BIT
;
2164 if (j0
< 0 || j0
> height_minus_1
) useBorderColor
|= J0BIT
;
2165 if (j1
< 0 || j1
> height_minus_1
) useBorderColor
|= J1BIT
;
2167 /* get four texel samples */
2168 if (useBorderColor
& (I0BIT
| J0BIT
))
2169 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2171 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
2173 if (useBorderColor
& (I1BIT
| J0BIT
))
2174 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2176 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
2178 if (useBorderColor
& (I0BIT
| J1BIT
))
2179 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2181 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
2183 if (useBorderColor
& (I1BIT
| J1BIT
))
2184 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2186 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
2188 /* compute interpolants */
2192 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2198 sample_lambda_rect( GLcontext
*ctx
,
2199 const struct gl_texture_object
*tObj
, GLuint n
,
2200 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2203 GLuint minStart
, minEnd
, magStart
, magEnd
;
2205 /* We only need lambda to decide between minification and magnification.
2206 * There is no mipmapping with rectangular textures.
2208 compute_min_mag_ranges(tObj
, n
, lambda
,
2209 &minStart
, &minEnd
, &magStart
, &magEnd
);
2211 if (minStart
< minEnd
) {
2212 if (tObj
->MinFilter
== GL_NEAREST
) {
2213 sample_nearest_rect( ctx
, tObj
, minEnd
- minStart
,
2214 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2217 sample_linear_rect( ctx
, tObj
, minEnd
- minStart
,
2218 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2221 if (magStart
< magEnd
) {
2222 if (tObj
->MagFilter
== GL_NEAREST
) {
2223 sample_nearest_rect( ctx
, tObj
, magEnd
- magStart
,
2224 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2227 sample_linear_rect( ctx
, tObj
, magEnd
- magStart
,
2228 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2236 * Sample a shadow/depth texture.
2239 sample_depth_texture( GLcontext
*ctx
,
2240 const struct gl_texture_object
*tObj
, GLuint n
,
2241 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2244 const GLint baseLevel
= tObj
->BaseLevel
;
2245 const struct gl_texture_image
*img
= tObj
->Image
[0][baseLevel
];
2246 const GLint width
= img
->Width
;
2247 const GLint height
= img
->Height
;
2254 ASSERT(tObj
->Image
[0][tObj
->BaseLevel
]->_BaseFormat
== GL_DEPTH_COMPONENT
||
2255 tObj
->Image
[0][tObj
->BaseLevel
]->_BaseFormat
== GL_DEPTH_STENCIL_EXT
);
2257 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
2258 tObj
->Target
== GL_TEXTURE_2D
||
2259 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
);
2261 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2263 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2265 /* XXX this could be precomputed and saved in the texture object */
2266 if (tObj
->CompareFlag
) {
2267 /* GL_SGIX_shadow */
2268 if (tObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
2269 function
= GL_LEQUAL
;
2272 ASSERT(tObj
->CompareOperator
== GL_TEXTURE_GEQUAL_R_SGIX
);
2273 function
= GL_GEQUAL
;
2276 else if (tObj
->CompareMode
== GL_COMPARE_R_TO_TEXTURE_ARB
) {
2278 function
= tObj
->CompareFunc
;
2281 function
= GL_NONE
; /* pass depth through as grayscale */
2284 if (tObj
->MagFilter
== GL_NEAREST
) {
2286 for (i
= 0; i
< n
; i
++) {
2287 GLfloat depthSample
;
2289 /* XXX fix for texture rectangle! */
2290 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0], width
, col
);
2291 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoords
[i
][1], height
, row
);
2292 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
) {
2293 img
->FetchTexelf(img
, col
, row
, 0, &depthSample
);
2296 depthSample
= tObj
->BorderColor
[0];
2301 result
= (texcoords
[i
][2] <= depthSample
) ? CHAN_MAX
: ambient
;
2304 result
= (texcoords
[i
][2] >= depthSample
) ? CHAN_MAX
: ambient
;
2307 result
= (texcoords
[i
][2] < depthSample
) ? CHAN_MAX
: ambient
;
2310 result
= (texcoords
[i
][2] > depthSample
) ? CHAN_MAX
: ambient
;
2313 result
= (texcoords
[i
][2] == depthSample
) ? CHAN_MAX
: ambient
;
2316 result
= (texcoords
[i
][2] != depthSample
) ? CHAN_MAX
: ambient
;
2325 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2328 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2332 switch (tObj
->DepthMode
) {
2334 texel
[i
][RCOMP
] = result
;
2335 texel
[i
][GCOMP
] = result
;
2336 texel
[i
][BCOMP
] = result
;
2337 texel
[i
][ACOMP
] = CHAN_MAX
;
2340 texel
[i
][RCOMP
] = result
;
2341 texel
[i
][GCOMP
] = result
;
2342 texel
[i
][BCOMP
] = result
;
2343 texel
[i
][ACOMP
] = result
;
2346 texel
[i
][RCOMP
] = 0;
2347 texel
[i
][GCOMP
] = 0;
2348 texel
[i
][BCOMP
] = 0;
2349 texel
[i
][ACOMP
] = result
;
2352 _mesa_problem(ctx
, "Bad depth texture mode");
2358 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
2359 for (i
= 0; i
< n
; i
++) {
2360 GLfloat depth00
, depth01
, depth10
, depth11
;
2361 GLint i0
, i1
, j0
, j1
;
2363 GLuint useBorderTexel
;
2365 /* XXX fix for texture rectangle! */
2366 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0], u
, width
, i0
, i1
);
2367 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoords
[i
][1], v
, height
,j0
, j1
);
2377 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
2378 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
2379 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
2380 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
2383 /* get four depth samples from the texture */
2384 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
2385 depth00
= tObj
->BorderColor
[0];
2388 img
->FetchTexelf(img
, i0
, j0
, 0, &depth00
);
2390 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
2391 depth10
= tObj
->BorderColor
[0];
2394 img
->FetchTexelf(img
, i1
, j0
, 0, &depth10
);
2396 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
2397 depth01
= tObj
->BorderColor
[0];
2400 img
->FetchTexelf(img
, i0
, j1
, 0, &depth01
);
2402 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
2403 depth11
= tObj
->BorderColor
[0];
2406 img
->FetchTexelf(img
, i1
, j1
, 0, &depth11
);
2410 /* compute a single weighted depth sample and do one comparison */
2411 const GLfloat a
= FRAC(u
+ 1.0F
);
2412 const GLfloat b
= FRAC(v
+ 1.0F
);
2413 const GLfloat depthSample
2414 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
2415 if ((depthSample
<= texcoords
[i
][2] && function
== GL_LEQUAL
) ||
2416 (depthSample
>= texcoords
[i
][2] && function
== GL_GEQUAL
)) {
2424 /* Do four depth/R comparisons and compute a weighted result.
2425 * If this touches on somebody's I.P., I'll remove this code
2428 const GLfloat d
= (CHAN_MAXF
- (GLfloat
) ambient
) * 0.25F
;
2429 GLfloat luminance
= CHAN_MAXF
;
2433 if (depth00
<= texcoords
[i
][2]) luminance
-= d
;
2434 if (depth01
<= texcoords
[i
][2]) luminance
-= d
;
2435 if (depth10
<= texcoords
[i
][2]) luminance
-= d
;
2436 if (depth11
<= texcoords
[i
][2]) luminance
-= d
;
2437 result
= (GLchan
) luminance
;
2440 if (depth00
>= texcoords
[i
][2]) luminance
-= d
;
2441 if (depth01
>= texcoords
[i
][2]) luminance
-= d
;
2442 if (depth10
>= texcoords
[i
][2]) luminance
-= d
;
2443 if (depth11
>= texcoords
[i
][2]) luminance
-= d
;
2444 result
= (GLchan
) luminance
;
2447 if (depth00
< texcoords
[i
][2]) luminance
-= d
;
2448 if (depth01
< texcoords
[i
][2]) luminance
-= d
;
2449 if (depth10
< texcoords
[i
][2]) luminance
-= d
;
2450 if (depth11
< texcoords
[i
][2]) luminance
-= d
;
2451 result
= (GLchan
) luminance
;
2454 if (depth00
> texcoords
[i
][2]) luminance
-= d
;
2455 if (depth01
> texcoords
[i
][2]) luminance
-= d
;
2456 if (depth10
> texcoords
[i
][2]) luminance
-= d
;
2457 if (depth11
> texcoords
[i
][2]) luminance
-= d
;
2458 result
= (GLchan
) luminance
;
2461 if (depth00
== texcoords
[i
][2]) luminance
-= d
;
2462 if (depth01
== texcoords
[i
][2]) luminance
-= d
;
2463 if (depth10
== texcoords
[i
][2]) luminance
-= d
;
2464 if (depth11
== texcoords
[i
][2]) luminance
-= d
;
2465 result
= (GLchan
) luminance
;
2468 if (depth00
!= texcoords
[i
][2]) luminance
-= d
;
2469 if (depth01
!= texcoords
[i
][2]) luminance
-= d
;
2470 if (depth10
!= texcoords
[i
][2]) luminance
-= d
;
2471 if (depth11
!= texcoords
[i
][2]) luminance
-= d
;
2472 result
= (GLchan
) luminance
;
2481 /* ordinary bilinear filtering */
2483 const GLfloat a
= FRAC(u
+ 1.0F
);
2484 const GLfloat b
= FRAC(v
+ 1.0F
);
2485 const GLfloat depthSample
2486 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
2487 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2491 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2496 switch (tObj
->DepthMode
) {
2498 texel
[i
][RCOMP
] = result
;
2499 texel
[i
][GCOMP
] = result
;
2500 texel
[i
][BCOMP
] = result
;
2501 texel
[i
][ACOMP
] = CHAN_MAX
;
2504 texel
[i
][RCOMP
] = result
;
2505 texel
[i
][GCOMP
] = result
;
2506 texel
[i
][BCOMP
] = result
;
2507 texel
[i
][ACOMP
] = result
;
2510 texel
[i
][RCOMP
] = 0;
2511 texel
[i
][GCOMP
] = 0;
2512 texel
[i
][BCOMP
] = 0;
2513 texel
[i
][ACOMP
] = result
;
2516 _mesa_problem(ctx
, "Bad depth texture mode");
2525 * Experimental depth texture sampling function.
2528 sample_depth_texture2(const GLcontext
*ctx
,
2529 const struct gl_texture_unit
*texUnit
,
2530 GLuint n
, const GLfloat texcoords
[][4],
2533 const struct gl_texture_object
*texObj
= texUnit
->_Current
;
2534 const GLint baseLevel
= texObj
->BaseLevel
;
2535 const struct gl_texture_image
*texImage
= texObj
->Image
[0][baseLevel
];
2536 const GLuint width
= texImage
->Width
;
2537 const GLuint height
= texImage
->Height
;
2539 GLboolean lequal
, gequal
;
2541 if (texObj
->Target
!= GL_TEXTURE_2D
) {
2542 _mesa_problem(ctx
, "only 2-D depth textures supported at this time");
2546 if (texObj
->MinFilter
!= texObj
->MagFilter
) {
2547 _mesa_problem(ctx
, "mipmapped depth textures not supported at this time");
2551 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
2552 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
2553 * isn't a depth texture.
2555 if (texImage
->_BaseFormat
!= GL_DEPTH_COMPONENT
) {
2556 _mesa_problem(ctx
,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
2560 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2562 if (texObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
2573 for (i
= 0; i
< n
; i
++) {
2575 GLint col
, row
, ii
, jj
, imin
, imax
, jmin
, jmax
, samples
, count
;
2578 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapS
, texcoords
[i
][0],
2580 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapT
, texcoords
[i
][1],
2588 if (imin
< 0) imin
= 0;
2589 if (imax
>= width
) imax
= width
- 1;
2590 if (jmin
< 0) jmin
= 0;
2591 if (jmax
>= height
) jmax
= height
- 1;
2593 samples
= (imax
- imin
+ 1) * (jmax
- jmin
+ 1);
2595 for (jj
= jmin
; jj
<= jmax
; jj
++) {
2596 for (ii
= imin
; ii
<= imax
; ii
++) {
2597 GLfloat depthSample
;
2598 texImage
->FetchTexelf(texImage
, ii
, jj
, 0, &depthSample
);
2599 if ((depthSample
<= r
[i
] && lequal
) ||
2600 (depthSample
>= r
[i
] && gequal
)) {
2606 w
= (GLfloat
) count
/ (GLfloat
) samples
;
2607 w
= CHAN_MAXF
- w
* (CHAN_MAXF
- (GLfloat
) ambient
);
2610 texel
[i
][RCOMP
] = lum
;
2611 texel
[i
][GCOMP
] = lum
;
2612 texel
[i
][BCOMP
] = lum
;
2613 texel
[i
][ACOMP
] = CHAN_MAX
;
2621 * We use this function when a texture object is in an "incomplete" state.
2622 * When a fragment program attempts to sample an incomplete texture we
2623 * return black (see issue 23 in GL_ARB_fragment_program spec).
2624 * Note: fragment programs don't observe the texture enable/disable flags.
2627 null_sample_func( GLcontext
*ctx
,
2628 const struct gl_texture_object
*tObj
, GLuint n
,
2629 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2637 for (i
= 0; i
< n
; i
++) {
2641 rgba
[i
][ACOMP
] = CHAN_MAX
;
2647 * Choose the texture sampling function for the given texture object.
2650 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
2651 const struct gl_texture_object
*t
)
2653 if (!t
|| !t
->Complete
) {
2654 return &null_sample_func
;
2657 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
2658 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->_BaseFormat
;
2660 switch (t
->Target
) {
2662 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
2663 return &sample_depth_texture
;
2665 else if (needLambda
) {
2666 return &sample_lambda_1d
;
2668 else if (t
->MinFilter
== GL_LINEAR
) {
2669 return &sample_linear_1d
;
2672 ASSERT(t
->MinFilter
== GL_NEAREST
);
2673 return &sample_nearest_1d
;
2676 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
2677 return &sample_depth_texture
;
2679 else if (needLambda
) {
2680 return &sample_lambda_2d
;
2682 else if (t
->MinFilter
== GL_LINEAR
) {
2683 return &sample_linear_2d
;
2686 /* check for a few optimized cases */
2687 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
2688 ASSERT(t
->MinFilter
== GL_NEAREST
);
2689 if (t
->WrapS
== GL_REPEAT
&&
2690 t
->WrapT
== GL_REPEAT
&&
2691 img
->_IsPowerOfTwo
&&
2693 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGB
) {
2694 return &opt_sample_rgb_2d
;
2696 else if (t
->WrapS
== GL_REPEAT
&&
2697 t
->WrapT
== GL_REPEAT
&&
2698 img
->_IsPowerOfTwo
&&
2700 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGBA
) {
2701 return &opt_sample_rgba_2d
;
2704 return &sample_nearest_2d
;
2709 return &sample_lambda_3d
;
2711 else if (t
->MinFilter
== GL_LINEAR
) {
2712 return &sample_linear_3d
;
2715 ASSERT(t
->MinFilter
== GL_NEAREST
);
2716 return &sample_nearest_3d
;
2718 case GL_TEXTURE_CUBE_MAP
:
2720 return &sample_lambda_cube
;
2722 else if (t
->MinFilter
== GL_LINEAR
) {
2723 return &sample_linear_cube
;
2726 ASSERT(t
->MinFilter
== GL_NEAREST
);
2727 return &sample_nearest_cube
;
2729 case GL_TEXTURE_RECTANGLE_NV
:
2731 return &sample_lambda_rect
;
2733 else if (t
->MinFilter
== GL_LINEAR
) {
2734 return &sample_linear_rect
;
2737 ASSERT(t
->MinFilter
== GL_NEAREST
);
2738 return &sample_nearest_rect
;
2742 "invalid target in _swrast_choose_texture_sample_func");
2743 return &null_sample_func
;