2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 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.
26 #include "main/glheader.h"
27 #include "main/context.h"
28 #include "main/colormac.h"
29 #include "main/imports.h"
30 #include "main/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 * If A is a signed integer, A % B doesn't give the right value for A < 0
217 * (in terms of texture repeat). Just casting to unsigned fixes that.
219 #define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
223 * Used to compute texel locations for linear sampling.
225 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
226 * S = texcoord in [0,1]
227 * SIZE = width (or height or depth) of texture
229 * U = texcoord in [0, width]
230 * I0, I1 = two nearest texel indexes
232 #define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \
234 switch (wrapMode) { \
236 U = S * SIZE - 0.5F; \
237 if (img->_IsPowerOfTwo) { \
238 I0 = IFLOOR(U) & (SIZE - 1); \
239 I1 = (I0 + 1) & (SIZE - 1); \
242 I0 = REMAINDER(IFLOOR(U), SIZE); \
243 I1 = REMAINDER(I0 + 1, SIZE); \
246 case GL_CLAMP_TO_EDGE: \
249 else if (S >= 1.0F) \
250 U = (GLfloat) SIZE; \
258 if (I1 >= (GLint) SIZE) \
261 case GL_CLAMP_TO_BORDER: \
263 const GLfloat min = -1.0F / (2.0F * SIZE); \
264 const GLfloat max = 1.0F - min; \
276 case GL_MIRRORED_REPEAT: \
278 const GLint flr = IFLOOR(S); \
280 U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
282 U = S - (GLfloat) flr; /* flr is even */ \
283 U = (U * SIZE) - 0.5F; \
288 if (I1 >= (GLint) SIZE) \
292 case GL_MIRROR_CLAMP_EXT: \
295 U = (GLfloat) SIZE; \
302 case GL_MIRROR_CLAMP_TO_EDGE_EXT: \
305 U = (GLfloat) SIZE; \
313 if (I1 >= (GLint) SIZE) \
316 case GL_MIRROR_CLAMP_TO_BORDER_EXT: \
318 const GLfloat min = -1.0F / (2.0F * SIZE); \
319 const GLfloat max = 1.0F - min; \
335 else if (S >= 1.0F) \
336 U = (GLfloat) SIZE; \
344 _mesa_problem(ctx, "Bad wrap mode"); \
351 * Used to compute texel location for nearest sampling.
353 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
355 switch (wrapMode) { \
357 /* s limited to [0,1) */ \
358 /* i limited to [0,size-1] */ \
359 I = IFLOOR(S * SIZE); \
360 if (img->_IsPowerOfTwo) \
363 I = REMAINDER(I, SIZE); \
365 case GL_CLAMP_TO_EDGE: \
367 /* s limited to [min,max] */ \
368 /* i limited to [0, size-1] */ \
369 const GLfloat min = 1.0F / (2.0F * SIZE); \
370 const GLfloat max = 1.0F - min; \
376 I = IFLOOR(S * SIZE); \
379 case GL_CLAMP_TO_BORDER: \
381 /* s limited to [min,max] */ \
382 /* i limited to [-1, size] */ \
383 const GLfloat min = -1.0F / (2.0F * SIZE); \
384 const GLfloat max = 1.0F - min; \
390 I = IFLOOR(S * SIZE); \
393 case GL_MIRRORED_REPEAT: \
395 const GLfloat min = 1.0F / (2.0F * SIZE); \
396 const GLfloat max = 1.0F - min; \
397 const GLint flr = IFLOOR(S); \
400 u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
402 u = S - (GLfloat) flr; /* flr is even */ \
408 I = IFLOOR(u * SIZE); \
411 case GL_MIRROR_CLAMP_EXT: \
413 /* s limited to [0,1] */ \
414 /* i limited to [0,size-1] */ \
415 const GLfloat u = FABSF(S); \
418 else if (u >= 1.0F) \
421 I = IFLOOR(u * SIZE); \
424 case GL_MIRROR_CLAMP_TO_EDGE_EXT: \
426 /* s limited to [min,max] */ \
427 /* i limited to [0, size-1] */ \
428 const GLfloat min = 1.0F / (2.0F * SIZE); \
429 const GLfloat max = 1.0F - min; \
430 const GLfloat u = FABSF(S); \
436 I = IFLOOR(u * SIZE); \
439 case GL_MIRROR_CLAMP_TO_BORDER_EXT: \
441 /* s limited to [min,max] */ \
442 /* i limited to [0, size-1] */ \
443 const GLfloat min = -1.0F / (2.0F * SIZE); \
444 const GLfloat max = 1.0F - min; \
445 const GLfloat u = FABSF(S); \
451 I = IFLOOR(u * SIZE); \
455 /* s limited to [0,1] */ \
456 /* i limited to [0,size-1] */ \
459 else if (S >= 1.0F) \
462 I = IFLOOR(S * SIZE); \
465 _mesa_problem(ctx, "Bad wrap mode"); \
471 /* Power of two image sizes only */
472 #define COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(S, U, SIZE, I0, I1) \
474 U = S * SIZE - 0.5F; \
475 I0 = IFLOOR(U) & (SIZE - 1); \
476 I1 = (I0 + 1) & (SIZE - 1); \
481 * For linear interpolation between mipmap levels N and N+1, this function
485 linear_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
488 return tObj
->BaseLevel
;
489 else if (lambda
> tObj
->_MaxLambda
)
490 return (GLint
) (tObj
->BaseLevel
+ tObj
->_MaxLambda
);
492 return (GLint
) (tObj
->BaseLevel
+ lambda
);
497 * Compute the nearest mipmap level to take texels from.
500 nearest_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
506 else if (lambda
> tObj
->_MaxLambda
+ 0.4999F
)
507 l
= tObj
->_MaxLambda
+ 0.4999F
;
510 level
= (GLint
) (tObj
->BaseLevel
+ l
+ 0.5F
);
511 if (level
> tObj
->_MaxLevel
)
512 level
= tObj
->_MaxLevel
;
519 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
520 * see 1-pixel bands of improperly weighted linear-filtered textures.
521 * The tests/texwrap.c demo is a good test.
522 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
523 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
525 #define FRAC(f) ((f) - IFLOOR(f))
530 * Bitflags for texture border color sampling.
542 * The lambda[] array values are always monotonic. Either the whole span
543 * will be minified, magnified, or split between the two. This function
544 * determines the subranges in [0, n-1] that are to be minified or magnified.
547 compute_min_mag_ranges(const struct gl_texture_object
*tObj
,
548 GLuint n
, const GLfloat lambda
[],
549 GLuint
*minStart
, GLuint
*minEnd
,
550 GLuint
*magStart
, GLuint
*magEnd
)
552 GLfloat minMagThresh
;
554 /* we shouldn't be here if minfilter == magfilter */
555 ASSERT(tObj
->MinFilter
!= tObj
->MagFilter
);
557 /* This bit comes from the OpenGL spec: */
558 if (tObj
->MagFilter
== GL_LINEAR
559 && (tObj
->MinFilter
== GL_NEAREST_MIPMAP_NEAREST
||
560 tObj
->MinFilter
== GL_NEAREST_MIPMAP_LINEAR
)) {
568 /* DEBUG CODE: Verify that lambda[] is monotonic.
569 * We can't really use this because the inaccuracy in the LOG2 function
570 * causes this test to fail, yet the resulting texturing is correct.
574 printf("lambda delta = %g\n", lambda
[0] - lambda
[n
-1]);
575 if (lambda
[0] >= lambda
[n
-1]) { /* decreasing */
576 for (i
= 0; i
< n
- 1; i
++) {
577 ASSERT((GLint
) (lambda
[i
] * 10) >= (GLint
) (lambda
[i
+1] * 10));
580 else { /* increasing */
581 for (i
= 0; i
< n
- 1; i
++) {
582 ASSERT((GLint
) (lambda
[i
] * 10) <= (GLint
) (lambda
[i
+1] * 10));
588 if (lambda
[0] <= minMagThresh
&& (n
<= 1 || lambda
[n
-1] <= minMagThresh
)) {
589 /* magnification for whole span */
592 *minStart
= *minEnd
= 0;
594 else if (lambda
[0] > minMagThresh
&& (n
<=1 || lambda
[n
-1] > minMagThresh
)) {
595 /* minification for whole span */
598 *magStart
= *magEnd
= 0;
601 /* a mix of minification and magnification */
603 if (lambda
[0] > minMagThresh
) {
604 /* start with minification */
605 for (i
= 1; i
< n
; i
++) {
606 if (lambda
[i
] <= minMagThresh
)
615 /* start with magnification */
616 for (i
= 1; i
< n
; i
++) {
617 if (lambda
[i
] > minMagThresh
)
628 /* Verify the min/mag Start/End values
629 * We don't use this either (see above)
633 for (i
= 0; i
< n
; i
++) {
634 if (lambda
[i
] > minMagThresh
) {
636 ASSERT(i
>= *minStart
);
641 ASSERT(i
>= *magStart
);
650 /**********************************************************************/
651 /* 1-D Texture Sampling Functions */
652 /**********************************************************************/
655 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
658 sample_1d_nearest(GLcontext
*ctx
,
659 const struct gl_texture_object
*tObj
,
660 const struct gl_texture_image
*img
,
661 const GLfloat texcoord
[4], GLchan rgba
[4])
663 const GLint width
= img
->Width2
; /* without border, power of two */
665 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
666 /* skip over the border, if any */
668 if (i
< 0 || i
>= (GLint
) img
->Width
) {
669 /* Need this test for GL_CLAMP_TO_BORDER mode */
670 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
673 img
->FetchTexelc(img
, i
, 0, 0, rgba
);
679 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
682 sample_1d_linear(GLcontext
*ctx
,
683 const struct gl_texture_object
*tObj
,
684 const struct gl_texture_image
*img
,
685 const GLfloat texcoord
[4], GLchan rgba
[4])
687 const GLint width
= img
->Width2
;
690 GLbitfield useBorderColor
= 0x0;
692 GLchan t0
[4], t1
[4]; /* texels */
694 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
701 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
702 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
705 /* fetch texel colors */
706 if (useBorderColor
& I0BIT
) {
707 COPY_CHAN4(t0
, tObj
->_BorderChan
);
710 img
->FetchTexelc(img
, i0
, 0, 0, t0
);
712 if (useBorderColor
& I1BIT
) {
713 COPY_CHAN4(t1
, tObj
->_BorderChan
);
716 img
->FetchTexelc(img
, i1
, 0, 0, t1
);
720 lerp_rgba(rgba
, a
, t0
, t1
);
725 sample_1d_nearest_mipmap_nearest(GLcontext
*ctx
,
726 const struct gl_texture_object
*tObj
,
727 GLuint n
, const GLfloat texcoord
[][4],
728 const GLfloat lambda
[], GLchan rgba
[][4])
731 ASSERT(lambda
!= NULL
);
732 for (i
= 0; i
< n
; i
++) {
733 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
734 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
740 sample_1d_linear_mipmap_nearest(GLcontext
*ctx
,
741 const struct gl_texture_object
*tObj
,
742 GLuint n
, const GLfloat texcoord
[][4],
743 const GLfloat lambda
[], GLchan rgba
[][4])
746 ASSERT(lambda
!= NULL
);
747 for (i
= 0; i
< n
; i
++) {
748 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
749 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
755 sample_1d_nearest_mipmap_linear(GLcontext
*ctx
,
756 const struct gl_texture_object
*tObj
,
757 GLuint n
, const GLfloat texcoord
[][4],
758 const GLfloat lambda
[], GLchan rgba
[][4])
761 ASSERT(lambda
!= NULL
);
762 for (i
= 0; i
< n
; i
++) {
763 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
764 if (level
>= tObj
->_MaxLevel
) {
765 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
766 texcoord
[i
], rgba
[i
]);
770 const GLfloat f
= FRAC(lambda
[i
]);
771 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
772 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
773 lerp_rgba(rgba
[i
], f
, t0
, t1
);
781 sample_1d_linear_mipmap_linear(GLcontext
*ctx
,
782 const struct gl_texture_object
*tObj
,
783 GLuint n
, const GLfloat texcoord
[][4],
784 const GLfloat lambda
[], GLchan rgba
[][4])
787 ASSERT(lambda
!= NULL
);
788 for (i
= 0; i
< n
; i
++) {
789 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
790 if (level
>= tObj
->_MaxLevel
) {
791 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
792 texcoord
[i
], rgba
[i
]);
796 const GLfloat f
= FRAC(lambda
[i
]);
797 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
798 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
799 lerp_rgba(rgba
[i
], f
, t0
, t1
);
807 sample_nearest_1d( GLcontext
*ctx
,
808 const struct gl_texture_object
*tObj
, GLuint n
,
809 const GLfloat texcoords
[][4], const GLfloat lambda
[],
813 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
816 sample_1d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
823 sample_linear_1d( GLcontext
*ctx
,
824 const struct gl_texture_object
*tObj
, GLuint n
,
825 const GLfloat texcoords
[][4], const GLfloat lambda
[],
829 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
832 sample_1d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
838 * Given an (s) texture coordinate and lambda (level of detail) value,
839 * return a texture sample.
843 sample_lambda_1d( GLcontext
*ctx
,
844 const struct gl_texture_object
*tObj
, GLuint n
,
845 const GLfloat texcoords
[][4],
846 const GLfloat lambda
[], GLchan rgba
[][4] )
848 GLuint minStart
, minEnd
; /* texels with minification */
849 GLuint magStart
, magEnd
; /* texels with magnification */
852 ASSERT(lambda
!= NULL
);
853 compute_min_mag_ranges(tObj
, n
, lambda
,
854 &minStart
, &minEnd
, &magStart
, &magEnd
);
856 if (minStart
< minEnd
) {
857 /* do the minified texels */
858 const GLuint m
= minEnd
- minStart
;
859 switch (tObj
->MinFilter
) {
861 for (i
= minStart
; i
< minEnd
; i
++)
862 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
863 texcoords
[i
], rgba
[i
]);
866 for (i
= minStart
; i
< minEnd
; i
++)
867 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
868 texcoords
[i
], rgba
[i
]);
870 case GL_NEAREST_MIPMAP_NEAREST
:
871 sample_1d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
872 lambda
+ minStart
, rgba
+ minStart
);
874 case GL_LINEAR_MIPMAP_NEAREST
:
875 sample_1d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
876 lambda
+ minStart
, rgba
+ minStart
);
878 case GL_NEAREST_MIPMAP_LINEAR
:
879 sample_1d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
880 lambda
+ minStart
, rgba
+ minStart
);
882 case GL_LINEAR_MIPMAP_LINEAR
:
883 sample_1d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
884 lambda
+ minStart
, rgba
+ minStart
);
887 _mesa_problem(ctx
, "Bad min filter in sample_1d_texture");
892 if (magStart
< magEnd
) {
893 /* do the magnified texels */
894 switch (tObj
->MagFilter
) {
896 for (i
= magStart
; i
< magEnd
; i
++)
897 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
898 texcoords
[i
], rgba
[i
]);
901 for (i
= magStart
; i
< magEnd
; i
++)
902 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
903 texcoords
[i
], rgba
[i
]);
906 _mesa_problem(ctx
, "Bad mag filter in sample_1d_texture");
913 /**********************************************************************/
914 /* 2-D Texture Sampling Functions */
915 /**********************************************************************/
919 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
922 sample_2d_nearest(GLcontext
*ctx
,
923 const struct gl_texture_object
*tObj
,
924 const struct gl_texture_image
*img
,
925 const GLfloat texcoord
[4],
928 const GLint width
= img
->Width2
; /* without border, power of two */
929 const GLint height
= img
->Height2
; /* without border, power of two */
933 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
934 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
936 /* skip over the border, if any */
940 if (i
< 0 || i
>= (GLint
) img
->Width
|| j
< 0 || j
>= (GLint
) img
->Height
) {
941 /* Need this test for GL_CLAMP_TO_BORDER mode */
942 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
945 img
->FetchTexelc(img
, i
, j
, 0, rgba
);
952 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
953 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
956 sample_2d_linear(GLcontext
*ctx
,
957 const struct gl_texture_object
*tObj
,
958 const struct gl_texture_image
*img
,
959 const GLfloat texcoord
[4],
962 const GLint width
= img
->Width2
;
963 const GLint height
= img
->Height2
;
964 GLint i0
, j0
, i1
, j1
;
965 GLbitfield useBorderColor
= 0x0;
968 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
970 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
971 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
980 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
981 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
982 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
983 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
986 /* fetch four texel colors */
987 if (useBorderColor
& (I0BIT
| J0BIT
)) {
988 COPY_CHAN4(t00
, tObj
->_BorderChan
);
991 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
993 if (useBorderColor
& (I1BIT
| J0BIT
)) {
994 COPY_CHAN4(t10
, tObj
->_BorderChan
);
997 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
999 if (useBorderColor
& (I0BIT
| J1BIT
)) {
1000 COPY_CHAN4(t01
, tObj
->_BorderChan
);
1003 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1005 if (useBorderColor
& (I1BIT
| J1BIT
)) {
1006 COPY_CHAN4(t11
, tObj
->_BorderChan
);
1009 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1014 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1019 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1020 * We don't have to worry about the texture border.
1023 sample_2d_linear_repeat(GLcontext
*ctx
,
1024 const struct gl_texture_object
*tObj
,
1025 const struct gl_texture_image
*img
,
1026 const GLfloat texcoord
[4],
1029 const GLint width
= img
->Width2
;
1030 const GLint height
= img
->Height2
;
1031 GLint i0
, j0
, i1
, j1
;
1034 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
1038 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1039 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1040 ASSERT(img
->Border
== 0);
1041 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
1042 ASSERT(img
->_IsPowerOfTwo
);
1044 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[0], u
, width
, i0
, i1
);
1045 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[1], v
, height
, j0
, j1
);
1047 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
1048 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
1049 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1050 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1054 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1060 sample_2d_nearest_mipmap_nearest(GLcontext
*ctx
,
1061 const struct gl_texture_object
*tObj
,
1062 GLuint n
, const GLfloat texcoord
[][4],
1063 const GLfloat lambda
[], GLchan rgba
[][4])
1066 for (i
= 0; i
< n
; i
++) {
1067 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1068 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1075 sample_2d_linear_mipmap_nearest(GLcontext
*ctx
,
1076 const struct gl_texture_object
*tObj
,
1077 GLuint n
, const GLfloat texcoord
[][4],
1078 const GLfloat lambda
[], GLchan rgba
[][4])
1081 ASSERT(lambda
!= NULL
);
1082 for (i
= 0; i
< n
; i
++) {
1083 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1084 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1091 sample_2d_nearest_mipmap_linear(GLcontext
*ctx
,
1092 const struct gl_texture_object
*tObj
,
1093 GLuint n
, const GLfloat texcoord
[][4],
1094 const GLfloat lambda
[], GLchan rgba
[][4])
1097 ASSERT(lambda
!= NULL
);
1098 for (i
= 0; i
< n
; i
++) {
1099 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1100 if (level
>= tObj
->_MaxLevel
) {
1101 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1102 texcoord
[i
], rgba
[i
]);
1105 GLchan t0
[4], t1
[4]; /* texels */
1106 const GLfloat f
= FRAC(lambda
[i
]);
1107 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1108 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1109 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1116 /* Trilinear filtering */
1118 sample_2d_linear_mipmap_linear( GLcontext
*ctx
,
1119 const struct gl_texture_object
*tObj
,
1120 GLuint n
, const GLfloat texcoord
[][4],
1121 const GLfloat lambda
[], GLchan rgba
[][4] )
1124 ASSERT(lambda
!= NULL
);
1125 for (i
= 0; i
< n
; i
++) {
1126 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1127 if (level
>= tObj
->_MaxLevel
) {
1128 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1129 texcoord
[i
], rgba
[i
]);
1132 GLchan t0
[4], t1
[4]; /* texels */
1133 const GLfloat f
= FRAC(lambda
[i
]);
1134 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1135 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1136 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1143 sample_2d_linear_mipmap_linear_repeat( GLcontext
*ctx
,
1144 const struct gl_texture_object
*tObj
,
1145 GLuint n
, const GLfloat texcoord
[][4],
1146 const GLfloat lambda
[], GLchan rgba
[][4] )
1149 ASSERT(lambda
!= NULL
);
1150 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1151 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1152 for (i
= 0; i
< n
; i
++) {
1153 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1154 if (level
>= tObj
->_MaxLevel
) {
1155 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1156 texcoord
[i
], rgba
[i
]);
1159 GLchan t0
[4], t1
[4]; /* texels */
1160 const GLfloat f
= FRAC(lambda
[i
]);
1161 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1162 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1163 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1170 sample_nearest_2d( GLcontext
*ctx
,
1171 const struct gl_texture_object
*tObj
, GLuint n
,
1172 const GLfloat texcoords
[][4],
1173 const GLfloat lambda
[], GLchan rgba
[][4] )
1176 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1179 sample_2d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1186 sample_linear_2d( GLcontext
*ctx
,
1187 const struct gl_texture_object
*tObj
, GLuint n
,
1188 const GLfloat texcoords
[][4],
1189 const GLfloat lambda
[], GLchan rgba
[][4] )
1192 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1194 if (tObj
->WrapS
== GL_REPEAT
&&
1195 tObj
->WrapT
== GL_REPEAT
&&
1196 image
->_IsPowerOfTwo
&&
1197 image
->Border
== 0) {
1199 sample_2d_linear_repeat(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1204 sample_2d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1211 * Optimized 2-D texture sampling:
1212 * S and T wrap mode == GL_REPEAT
1213 * GL_NEAREST min/mag filter
1215 * RowStride == Width,
1219 opt_sample_rgb_2d( GLcontext
*ctx
,
1220 const struct gl_texture_object
*tObj
,
1221 GLuint n
, const GLfloat texcoords
[][4],
1222 const GLfloat lambda
[], GLchan rgba
[][4] )
1224 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1225 const GLfloat width
= (GLfloat
) img
->Width
;
1226 const GLfloat height
= (GLfloat
) img
->Height
;
1227 const GLint colMask
= img
->Width
- 1;
1228 const GLint rowMask
= img
->Height
- 1;
1229 const GLint shift
= img
->WidthLog2
;
1233 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1234 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1235 ASSERT(img
->Border
==0);
1236 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGB
);
1237 ASSERT(img
->_IsPowerOfTwo
);
1239 for (k
=0; k
<n
; k
++) {
1240 GLint i
= IFLOOR(texcoords
[k
][0] * width
) & colMask
;
1241 GLint j
= IFLOOR(texcoords
[k
][1] * height
) & rowMask
;
1242 GLint pos
= (j
<< shift
) | i
;
1243 GLchan
*texel
= ((GLchan
*) img
->Data
) + 3*pos
;
1244 rgba
[k
][RCOMP
] = texel
[0];
1245 rgba
[k
][GCOMP
] = texel
[1];
1246 rgba
[k
][BCOMP
] = texel
[2];
1252 * Optimized 2-D texture sampling:
1253 * S and T wrap mode == GL_REPEAT
1254 * GL_NEAREST min/mag filter
1256 * RowStride == Width,
1260 opt_sample_rgba_2d( GLcontext
*ctx
,
1261 const struct gl_texture_object
*tObj
,
1262 GLuint n
, const GLfloat texcoords
[][4],
1263 const GLfloat lambda
[], GLchan rgba
[][4] )
1265 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1266 const GLfloat width
= (GLfloat
) img
->Width
;
1267 const GLfloat height
= (GLfloat
) img
->Height
;
1268 const GLint colMask
= img
->Width
- 1;
1269 const GLint rowMask
= img
->Height
- 1;
1270 const GLint shift
= img
->WidthLog2
;
1274 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1275 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1276 ASSERT(img
->Border
==0);
1277 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGBA
);
1278 ASSERT(img
->_IsPowerOfTwo
);
1280 for (i
= 0; i
< n
; i
++) {
1281 const GLint col
= IFLOOR(texcoords
[i
][0] * width
) & colMask
;
1282 const GLint row
= IFLOOR(texcoords
[i
][1] * height
) & rowMask
;
1283 const GLint pos
= (row
<< shift
) | col
;
1284 const GLchan
*texel
= ((GLchan
*) img
->Data
) + (pos
<< 2); /* pos*4 */
1285 COPY_CHAN4(rgba
[i
], texel
);
1291 * Given an array of texture coordinate and lambda (level of detail)
1292 * values, return an array of texture sample.
1295 sample_lambda_2d( GLcontext
*ctx
,
1296 const struct gl_texture_object
*tObj
,
1297 GLuint n
, const GLfloat texcoords
[][4],
1298 const GLfloat lambda
[], GLchan rgba
[][4] )
1300 const struct gl_texture_image
*tImg
= tObj
->Image
[0][tObj
->BaseLevel
];
1301 GLuint minStart
, minEnd
; /* texels with minification */
1302 GLuint magStart
, magEnd
; /* texels with magnification */
1304 const GLboolean repeatNoBorderPOT
= (tObj
->WrapS
== GL_REPEAT
)
1305 && (tObj
->WrapT
== GL_REPEAT
)
1306 && (tImg
->Border
== 0 && (tImg
->Width
== tImg
->RowStride
))
1307 && (tImg
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
)
1308 && tImg
->_IsPowerOfTwo
;
1310 ASSERT(lambda
!= NULL
);
1311 compute_min_mag_ranges(tObj
, n
, lambda
,
1312 &minStart
, &minEnd
, &magStart
, &magEnd
);
1314 if (minStart
< minEnd
) {
1315 /* do the minified texels */
1316 const GLuint m
= minEnd
- minStart
;
1317 switch (tObj
->MinFilter
) {
1319 if (repeatNoBorderPOT
) {
1320 switch (tImg
->TexFormat
->MesaFormat
) {
1321 case MESA_FORMAT_RGB
:
1322 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1323 NULL
, rgba
+ minStart
);
1325 case MESA_FORMAT_RGBA
:
1326 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1327 NULL
, rgba
+ minStart
);
1330 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1331 NULL
, rgba
+ minStart
);
1335 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1336 NULL
, rgba
+ minStart
);
1340 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1341 NULL
, rgba
+ minStart
);
1343 case GL_NEAREST_MIPMAP_NEAREST
:
1344 sample_2d_nearest_mipmap_nearest(ctx
, tObj
, m
,
1345 texcoords
+ minStart
,
1346 lambda
+ minStart
, rgba
+ minStart
);
1348 case GL_LINEAR_MIPMAP_NEAREST
:
1349 sample_2d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1350 lambda
+ minStart
, rgba
+ minStart
);
1352 case GL_NEAREST_MIPMAP_LINEAR
:
1353 sample_2d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1354 lambda
+ minStart
, rgba
+ minStart
);
1356 case GL_LINEAR_MIPMAP_LINEAR
:
1357 if (repeatNoBorderPOT
)
1358 sample_2d_linear_mipmap_linear_repeat(ctx
, tObj
, m
,
1359 texcoords
+ minStart
, lambda
+ minStart
, rgba
+ minStart
);
1361 sample_2d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1362 lambda
+ minStart
, rgba
+ minStart
);
1365 _mesa_problem(ctx
, "Bad min filter in sample_2d_texture");
1370 if (magStart
< magEnd
) {
1371 /* do the magnified texels */
1372 const GLuint m
= magEnd
- magStart
;
1374 switch (tObj
->MagFilter
) {
1376 if (repeatNoBorderPOT
) {
1377 switch (tImg
->TexFormat
->MesaFormat
) {
1378 case MESA_FORMAT_RGB
:
1379 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1380 NULL
, rgba
+ magStart
);
1382 case MESA_FORMAT_RGBA
:
1383 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1384 NULL
, rgba
+ magStart
);
1387 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1388 NULL
, rgba
+ magStart
);
1392 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1393 NULL
, rgba
+ magStart
);
1397 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1398 NULL
, rgba
+ magStart
);
1401 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_2d");
1408 /**********************************************************************/
1409 /* 3-D Texture Sampling Functions */
1410 /**********************************************************************/
1413 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1416 sample_3d_nearest(GLcontext
*ctx
,
1417 const struct gl_texture_object
*tObj
,
1418 const struct gl_texture_image
*img
,
1419 const GLfloat texcoord
[4],
1422 const GLint width
= img
->Width2
; /* without border, power of two */
1423 const GLint height
= img
->Height2
; /* without border, power of two */
1424 const GLint depth
= img
->Depth2
; /* without border, power of two */
1428 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
1429 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
1430 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapR
, texcoord
[2], depth
, k
);
1432 if (i
< 0 || i
>= (GLint
) img
->Width
||
1433 j
< 0 || j
>= (GLint
) img
->Height
||
1434 k
< 0 || k
>= (GLint
) img
->Depth
) {
1435 /* Need this test for GL_CLAMP_TO_BORDER mode */
1436 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
1439 img
->FetchTexelc(img
, i
, j
, k
, rgba
);
1446 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1449 sample_3d_linear(GLcontext
*ctx
,
1450 const struct gl_texture_object
*tObj
,
1451 const struct gl_texture_image
*img
,
1452 const GLfloat texcoord
[4],
1455 const GLint width
= img
->Width2
;
1456 const GLint height
= img
->Height2
;
1457 const GLint depth
= img
->Depth2
;
1458 GLint i0
, j0
, k0
, i1
, j1
, k1
;
1459 GLbitfield useBorderColor
= 0x0;
1462 GLchan t000
[4], t010
[4], t001
[4], t011
[4];
1463 GLchan t100
[4], t110
[4], t101
[4], t111
[4];
1465 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
1466 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
1467 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapR
, texcoord
[2], w
, depth
, k0
, k1
);
1478 /* check if sampling texture border color */
1479 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1480 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1481 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1482 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1483 if (k0
< 0 || k0
>= depth
) useBorderColor
|= K0BIT
;
1484 if (k1
< 0 || k1
>= depth
) useBorderColor
|= K1BIT
;
1488 if (useBorderColor
& (I0BIT
| J0BIT
| K0BIT
)) {
1489 COPY_CHAN4(t000
, tObj
->_BorderChan
);
1492 img
->FetchTexelc(img
, i0
, j0
, k0
, t000
);
1494 if (useBorderColor
& (I1BIT
| J0BIT
| K0BIT
)) {
1495 COPY_CHAN4(t100
, tObj
->_BorderChan
);
1498 img
->FetchTexelc(img
, i1
, j0
, k0
, t100
);
1500 if (useBorderColor
& (I0BIT
| J1BIT
| K0BIT
)) {
1501 COPY_CHAN4(t010
, tObj
->_BorderChan
);
1504 img
->FetchTexelc(img
, i0
, j1
, k0
, t010
);
1506 if (useBorderColor
& (I1BIT
| J1BIT
| K0BIT
)) {
1507 COPY_CHAN4(t110
, tObj
->_BorderChan
);
1510 img
->FetchTexelc(img
, i1
, j1
, k0
, t110
);
1513 if (useBorderColor
& (I0BIT
| J0BIT
| K1BIT
)) {
1514 COPY_CHAN4(t001
, tObj
->_BorderChan
);
1517 img
->FetchTexelc(img
, i0
, j0
, k1
, t001
);
1519 if (useBorderColor
& (I1BIT
| J0BIT
| K1BIT
)) {
1520 COPY_CHAN4(t101
, tObj
->_BorderChan
);
1523 img
->FetchTexelc(img
, i1
, j0
, k1
, t101
);
1525 if (useBorderColor
& (I0BIT
| J1BIT
| K1BIT
)) {
1526 COPY_CHAN4(t011
, tObj
->_BorderChan
);
1529 img
->FetchTexelc(img
, i0
, j1
, k1
, t011
);
1531 if (useBorderColor
& (I1BIT
| J1BIT
| K1BIT
)) {
1532 COPY_CHAN4(t111
, tObj
->_BorderChan
);
1535 img
->FetchTexelc(img
, i1
, j1
, k1
, t111
);
1538 /* trilinear interpolation of samples */
1542 lerp_rgba_3d(rgba
, a
, b
, c
, t000
, t100
, t010
, t110
, t001
, t101
, t011
, t111
);
1548 sample_3d_nearest_mipmap_nearest(GLcontext
*ctx
,
1549 const struct gl_texture_object
*tObj
,
1550 GLuint n
, const GLfloat texcoord
[][4],
1551 const GLfloat lambda
[], GLchan rgba
[][4] )
1554 for (i
= 0; i
< n
; i
++) {
1555 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1556 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1562 sample_3d_linear_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])
1568 ASSERT(lambda
!= NULL
);
1569 for (i
= 0; i
< n
; i
++) {
1570 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1571 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1577 sample_3d_nearest_mipmap_linear(GLcontext
*ctx
,
1578 const struct gl_texture_object
*tObj
,
1579 GLuint n
, const GLfloat texcoord
[][4],
1580 const GLfloat lambda
[], GLchan rgba
[][4])
1583 ASSERT(lambda
!= NULL
);
1584 for (i
= 0; i
< n
; i
++) {
1585 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1586 if (level
>= tObj
->_MaxLevel
) {
1587 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1588 texcoord
[i
], rgba
[i
]);
1591 GLchan t0
[4], t1
[4]; /* texels */
1592 const GLfloat f
= FRAC(lambda
[i
]);
1593 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1594 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1595 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1602 sample_3d_linear_mipmap_linear(GLcontext
*ctx
,
1603 const struct gl_texture_object
*tObj
,
1604 GLuint n
, const GLfloat texcoord
[][4],
1605 const GLfloat lambda
[], GLchan rgba
[][4])
1608 ASSERT(lambda
!= NULL
);
1609 for (i
= 0; i
< n
; i
++) {
1610 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1611 if (level
>= tObj
->_MaxLevel
) {
1612 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1613 texcoord
[i
], rgba
[i
]);
1616 GLchan t0
[4], t1
[4]; /* texels */
1617 const GLfloat f
= FRAC(lambda
[i
]);
1618 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1619 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1620 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1627 sample_nearest_3d(GLcontext
*ctx
,
1628 const struct gl_texture_object
*tObj
, GLuint n
,
1629 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1633 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1636 sample_3d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1643 sample_linear_3d( GLcontext
*ctx
,
1644 const struct gl_texture_object
*tObj
, GLuint n
,
1645 const GLfloat texcoords
[][4],
1646 const GLfloat lambda
[], GLchan rgba
[][4] )
1649 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1652 sample_3d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1658 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1659 * return a texture sample.
1662 sample_lambda_3d( GLcontext
*ctx
,
1663 const struct gl_texture_object
*tObj
, GLuint n
,
1664 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1667 GLuint minStart
, minEnd
; /* texels with minification */
1668 GLuint magStart
, magEnd
; /* texels with magnification */
1671 ASSERT(lambda
!= NULL
);
1672 compute_min_mag_ranges(tObj
, n
, lambda
,
1673 &minStart
, &minEnd
, &magStart
, &magEnd
);
1675 if (minStart
< minEnd
) {
1676 /* do the minified texels */
1677 GLuint m
= minEnd
- minStart
;
1678 switch (tObj
->MinFilter
) {
1680 for (i
= minStart
; i
< minEnd
; i
++)
1681 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1682 texcoords
[i
], rgba
[i
]);
1685 for (i
= minStart
; i
< minEnd
; i
++)
1686 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1687 texcoords
[i
], rgba
[i
]);
1689 case GL_NEAREST_MIPMAP_NEAREST
:
1690 sample_3d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1691 lambda
+ minStart
, rgba
+ minStart
);
1693 case GL_LINEAR_MIPMAP_NEAREST
:
1694 sample_3d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1695 lambda
+ minStart
, rgba
+ minStart
);
1697 case GL_NEAREST_MIPMAP_LINEAR
:
1698 sample_3d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1699 lambda
+ minStart
, rgba
+ minStart
);
1701 case GL_LINEAR_MIPMAP_LINEAR
:
1702 sample_3d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1703 lambda
+ minStart
, rgba
+ minStart
);
1706 _mesa_problem(ctx
, "Bad min filter in sample_3d_texture");
1711 if (magStart
< magEnd
) {
1712 /* do the magnified texels */
1713 switch (tObj
->MagFilter
) {
1715 for (i
= magStart
; i
< magEnd
; i
++)
1716 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1717 texcoords
[i
], rgba
[i
]);
1720 for (i
= magStart
; i
< magEnd
; i
++)
1721 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1722 texcoords
[i
], rgba
[i
]);
1725 _mesa_problem(ctx
, "Bad mag filter in sample_3d_texture");
1732 /**********************************************************************/
1733 /* Texture Cube Map Sampling Functions */
1734 /**********************************************************************/
1737 * Choose one of six sides of a texture cube map given the texture
1738 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1741 static const struct gl_texture_image
**
1742 choose_cube_face(const struct gl_texture_object
*texObj
,
1743 const GLfloat texcoord
[4], GLfloat newCoord
[4])
1747 direction target sc tc ma
1748 ---------- ------------------------------- --- --- ---
1749 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1750 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1751 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1752 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1753 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1754 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1756 const GLfloat rx
= texcoord
[0];
1757 const GLfloat ry
= texcoord
[1];
1758 const GLfloat rz
= texcoord
[2];
1759 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
1763 if (arx
> ary
&& arx
> arz
) {
1777 else if (ary
> arx
&& ary
> arz
) {
1806 newCoord
[0] = ( sc
/ ma
+ 1.0F
) * 0.5F
;
1807 newCoord
[1] = ( tc
/ ma
+ 1.0F
) * 0.5F
;
1808 return (const struct gl_texture_image
**) texObj
->Image
[face
];
1813 sample_nearest_cube(GLcontext
*ctx
,
1814 const struct gl_texture_object
*tObj
, GLuint n
,
1815 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1820 for (i
= 0; i
< n
; i
++) {
1821 const struct gl_texture_image
**images
;
1822 GLfloat newCoord
[4];
1823 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1824 sample_2d_nearest(ctx
, tObj
, images
[tObj
->BaseLevel
],
1831 sample_linear_cube(GLcontext
*ctx
,
1832 const struct gl_texture_object
*tObj
, GLuint n
,
1833 const GLfloat texcoords
[][4],
1834 const GLfloat lambda
[], GLchan rgba
[][4])
1838 for (i
= 0; i
< n
; i
++) {
1839 const struct gl_texture_image
**images
;
1840 GLfloat newCoord
[4];
1841 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1842 sample_2d_linear(ctx
, tObj
, images
[tObj
->BaseLevel
],
1849 sample_cube_nearest_mipmap_nearest(GLcontext
*ctx
,
1850 const struct gl_texture_object
*tObj
,
1851 GLuint n
, const GLfloat texcoord
[][4],
1852 const GLfloat lambda
[], GLchan rgba
[][4])
1855 ASSERT(lambda
!= NULL
);
1856 for (i
= 0; i
< n
; i
++) {
1857 const struct gl_texture_image
**images
;
1858 GLfloat newCoord
[4];
1860 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1862 /* XXX we actually need to recompute lambda here based on the newCoords.
1863 * But we would need the texcoords of adjacent fragments to compute that
1864 * properly, and we don't have those here.
1865 * For now, do an approximation: subtracting 1 from the chosen mipmap
1866 * level seems to work in some test cases.
1867 * The same adjustment is done in the next few functions.
1869 level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1870 level
= MAX2(level
- 1, 0);
1872 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1878 sample_cube_linear_mipmap_nearest(GLcontext
*ctx
,
1879 const struct gl_texture_object
*tObj
,
1880 GLuint n
, const GLfloat texcoord
[][4],
1881 const GLfloat lambda
[], GLchan rgba
[][4])
1884 ASSERT(lambda
!= NULL
);
1885 for (i
= 0; i
< n
; i
++) {
1886 const struct gl_texture_image
**images
;
1887 GLfloat newCoord
[4];
1888 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1889 level
= MAX2(level
- 1, 0); /* see comment above */
1890 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1891 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1897 sample_cube_nearest_mipmap_linear(GLcontext
*ctx
,
1898 const struct gl_texture_object
*tObj
,
1899 GLuint n
, const GLfloat texcoord
[][4],
1900 const GLfloat lambda
[], GLchan rgba
[][4])
1903 ASSERT(lambda
!= NULL
);
1904 for (i
= 0; i
< n
; i
++) {
1905 const struct gl_texture_image
**images
;
1906 GLfloat newCoord
[4];
1907 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1908 level
= MAX2(level
- 1, 0); /* see comment above */
1909 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1910 if (level
>= tObj
->_MaxLevel
) {
1911 sample_2d_nearest(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1915 GLchan t0
[4], t1
[4]; /* texels */
1916 const GLfloat f
= FRAC(lambda
[i
]);
1917 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, t0
);
1918 sample_2d_nearest(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1919 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1926 sample_cube_linear_mipmap_linear(GLcontext
*ctx
,
1927 const struct gl_texture_object
*tObj
,
1928 GLuint n
, const GLfloat texcoord
[][4],
1929 const GLfloat lambda
[], GLchan rgba
[][4])
1932 ASSERT(lambda
!= NULL
);
1933 for (i
= 0; i
< n
; i
++) {
1934 const struct gl_texture_image
**images
;
1935 GLfloat newCoord
[4];
1936 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1937 level
= MAX2(level
- 1, 0); /* see comment above */
1938 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1939 if (level
>= tObj
->_MaxLevel
) {
1940 sample_2d_linear(ctx
, tObj
, images
[tObj
->_MaxLevel
],
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
);
1955 sample_lambda_cube( GLcontext
*ctx
,
1956 const struct gl_texture_object
*tObj
, GLuint n
,
1957 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1960 GLuint minStart
, minEnd
; /* texels with minification */
1961 GLuint magStart
, magEnd
; /* texels with magnification */
1963 ASSERT(lambda
!= NULL
);
1964 compute_min_mag_ranges(tObj
, n
, lambda
,
1965 &minStart
, &minEnd
, &magStart
, &magEnd
);
1967 if (minStart
< minEnd
) {
1968 /* do the minified texels */
1969 const GLuint m
= minEnd
- minStart
;
1970 switch (tObj
->MinFilter
) {
1972 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1973 lambda
+ minStart
, rgba
+ minStart
);
1976 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1977 lambda
+ minStart
, rgba
+ minStart
);
1979 case GL_NEAREST_MIPMAP_NEAREST
:
1980 sample_cube_nearest_mipmap_nearest(ctx
, tObj
, m
,
1981 texcoords
+ minStart
,
1982 lambda
+ minStart
, rgba
+ minStart
);
1984 case GL_LINEAR_MIPMAP_NEAREST
:
1985 sample_cube_linear_mipmap_nearest(ctx
, tObj
, m
,
1986 texcoords
+ minStart
,
1987 lambda
+ minStart
, rgba
+ minStart
);
1989 case GL_NEAREST_MIPMAP_LINEAR
:
1990 sample_cube_nearest_mipmap_linear(ctx
, tObj
, m
,
1991 texcoords
+ minStart
,
1992 lambda
+ minStart
, rgba
+ minStart
);
1994 case GL_LINEAR_MIPMAP_LINEAR
:
1995 sample_cube_linear_mipmap_linear(ctx
, tObj
, m
,
1996 texcoords
+ minStart
,
1997 lambda
+ minStart
, rgba
+ minStart
);
2000 _mesa_problem(ctx
, "Bad min filter in sample_lambda_cube");
2004 if (magStart
< magEnd
) {
2005 /* do the magnified texels */
2006 const GLuint m
= magEnd
- magStart
;
2007 switch (tObj
->MagFilter
) {
2009 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2010 lambda
+ magStart
, rgba
+ magStart
);
2013 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2014 lambda
+ magStart
, rgba
+ magStart
);
2017 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_cube");
2023 /**********************************************************************/
2024 /* Texture Rectangle Sampling Functions */
2025 /**********************************************************************/
2029 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
2032 clamp_rect_coord_nearest(GLenum wrapMode
, GLfloat coord
, GLint max
)
2034 if (wrapMode
== GL_CLAMP
) {
2035 return IFLOOR( CLAMP(coord
, 0.0F
, max
- 1) );
2037 else if (wrapMode
== GL_CLAMP_TO_EDGE
) {
2038 return IFLOOR( CLAMP(coord
, 0.5F
, max
- 0.5F
) );
2041 return IFLOOR( CLAMP(coord
, -0.5F
, max
+ 0.5F
) );
2047 * As above, but GL_LINEAR filtering.
2050 clamp_rect_coord_linear(GLenum wrapMode
, GLfloat coord
, GLint max
,
2051 GLint
*i0out
, GLint
*i1out
)
2055 if (wrapMode
== GL_CLAMP
) {
2056 /* Not exactly what the spec says, but it matches NVIDIA output */
2057 fcol
= CLAMP(coord
- 0.5F
, 0.0, max
-1);
2061 else if (wrapMode
== GL_CLAMP_TO_EDGE
) {
2062 fcol
= CLAMP(coord
, 0.5F
, max
- 0.5F
);
2070 ASSERT(wrapMode
== GL_CLAMP_TO_BORDER
);
2071 fcol
= CLAMP(coord
, -0.5F
, max
+ 0.5F
);
2082 sample_nearest_rect(GLcontext
*ctx
,
2083 const struct gl_texture_object
*tObj
, GLuint n
,
2084 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2087 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2088 const GLfloat width
= (GLfloat
) img
->Width
;
2089 const GLfloat height
= (GLfloat
) img
->Height
;
2090 const GLint width_minus_1
= img
->Width
- 1;
2091 const GLint height_minus_1
= img
->Height
- 1;
2097 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2098 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2099 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2100 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2101 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2102 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2103 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2105 for (i
= 0; i
< n
; i
++) {
2107 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2108 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2109 if (col
< 0 || col
> width_minus_1
|| row
< 0 || row
> height_minus_1
)
2110 COPY_CHAN4(rgba
[i
], tObj
->_BorderChan
);
2112 img
->FetchTexelc(img
, col
, row
, 0, rgba
[i
]);
2118 sample_linear_rect(GLcontext
*ctx
,
2119 const struct gl_texture_object
*tObj
, GLuint n
,
2120 const GLfloat texcoords
[][4],
2121 const GLfloat lambda
[], GLchan rgba
[][4])
2123 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2124 const GLfloat width
= (GLfloat
) img
->Width
;
2125 const GLfloat height
= (GLfloat
) img
->Height
;
2126 const GLint width_minus_1
= img
->Width
- 1;
2127 const GLint height_minus_1
= img
->Height
- 1;
2133 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2134 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2135 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2136 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2137 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2138 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2139 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2141 /* XXX lots of opportunity for optimization in this loop */
2142 for (i
= 0; i
< n
; i
++) {
2144 GLint i0
, j0
, i1
, j1
;
2145 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2147 GLbitfield useBorderColor
= 0x0;
2149 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2150 if (tObj
->WrapS
== GL_CLAMP
) {
2151 /* Not exactly what the spec says, but it matches NVIDIA output */
2152 fcol
= CLAMP(texcoords
[i
][0] - 0.5F
, 0.0, width_minus_1
);
2156 else if (tObj
->WrapS
== GL_CLAMP_TO_EDGE
) {
2157 fcol
= CLAMP(texcoords
[i
][0], 0.5F
, width
- 0.5F
);
2161 if (i1
> width_minus_1
)
2165 ASSERT(tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2166 fcol
= CLAMP(texcoords
[i
][0], -0.5F
, width
+ 0.5F
);
2172 if (tObj
->WrapT
== GL_CLAMP
) {
2173 /* Not exactly what the spec says, but it matches NVIDIA output */
2174 frow
= CLAMP(texcoords
[i
][1] - 0.5F
, 0.0, width_minus_1
);
2178 else if (tObj
->WrapT
== GL_CLAMP_TO_EDGE
) {
2179 frow
= CLAMP(texcoords
[i
][1], 0.5F
, height
- 0.5F
);
2183 if (j1
> height_minus_1
)
2184 j1
= height_minus_1
;
2187 ASSERT(tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2188 frow
= CLAMP(texcoords
[i
][1], -0.5F
, height
+ 0.5F
);
2194 /* compute integer rows/columns */
2195 if (i0
< 0 || i0
> width_minus_1
) useBorderColor
|= I0BIT
;
2196 if (i1
< 0 || i1
> width_minus_1
) useBorderColor
|= I1BIT
;
2197 if (j0
< 0 || j0
> height_minus_1
) useBorderColor
|= J0BIT
;
2198 if (j1
< 0 || j1
> height_minus_1
) useBorderColor
|= J1BIT
;
2200 /* get four texel samples */
2201 if (useBorderColor
& (I0BIT
| J0BIT
))
2202 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2204 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
2206 if (useBorderColor
& (I1BIT
| J0BIT
))
2207 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2209 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
2211 if (useBorderColor
& (I0BIT
| J1BIT
))
2212 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2214 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
2216 if (useBorderColor
& (I1BIT
| J1BIT
))
2217 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2219 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
2221 /* compute interpolants */
2225 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2231 sample_lambda_rect( GLcontext
*ctx
,
2232 const struct gl_texture_object
*tObj
, GLuint n
,
2233 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2236 GLuint minStart
, minEnd
, magStart
, magEnd
;
2238 /* We only need lambda to decide between minification and magnification.
2239 * There is no mipmapping with rectangular textures.
2241 compute_min_mag_ranges(tObj
, n
, lambda
,
2242 &minStart
, &minEnd
, &magStart
, &magEnd
);
2244 if (minStart
< minEnd
) {
2245 if (tObj
->MinFilter
== GL_NEAREST
) {
2246 sample_nearest_rect( ctx
, tObj
, minEnd
- minStart
,
2247 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2250 sample_linear_rect( ctx
, tObj
, minEnd
- minStart
,
2251 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2254 if (magStart
< magEnd
) {
2255 if (tObj
->MagFilter
== GL_NEAREST
) {
2256 sample_nearest_rect( ctx
, tObj
, magEnd
- magStart
,
2257 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2260 sample_linear_rect( ctx
, tObj
, magEnd
- magStart
,
2261 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2268 /**********************************************************************/
2269 /* 2D Texture Array Sampling Functions */
2270 /**********************************************************************/
2273 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2276 sample_2d_array_nearest(GLcontext
*ctx
,
2277 const struct gl_texture_object
*tObj
,
2278 const struct gl_texture_image
*img
,
2279 const GLfloat texcoord
[4],
2282 const GLint width
= img
->Width2
; /* without border, power of two */
2283 const GLint height
= img
->Height2
; /* without border, power of two */
2284 const GLint depth
= img
->Depth
;
2289 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
2290 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
2291 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2293 if (i
< 0 || i
>= (GLint
) img
->Width
||
2294 j
< 0 || j
>= (GLint
) img
->Height
||
2295 array
< 0 || array
>= (GLint
) img
->Depth
) {
2296 /* Need this test for GL_CLAMP_TO_BORDER mode */
2297 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2300 img
->FetchTexelc(img
, i
, j
, array
, rgba
);
2307 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2310 sample_2d_array_linear(GLcontext
*ctx
,
2311 const struct gl_texture_object
*tObj
,
2312 const struct gl_texture_image
*img
,
2313 const GLfloat texcoord
[4],
2316 const GLint width
= img
->Width2
;
2317 const GLint height
= img
->Height2
;
2318 const GLint depth
= img
->Depth
;
2319 GLint i0
, j0
, i1
, j1
;
2321 GLbitfield useBorderColor
= 0x0;
2324 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2326 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
2327 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
2328 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2330 if (array
< 0 || array
>= depth
) {
2331 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2341 /* check if sampling texture border color */
2342 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2343 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2344 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2345 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2349 if (useBorderColor
& (I0BIT
| J0BIT
)) {
2350 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2353 img
->FetchTexelc(img
, i0
, j0
, array
, t00
);
2355 if (useBorderColor
& (I1BIT
| J0BIT
)) {
2356 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2359 img
->FetchTexelc(img
, i1
, j0
, array
, t10
);
2361 if (useBorderColor
& (I0BIT
| J1BIT
)) {
2362 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2365 img
->FetchTexelc(img
, i0
, j1
, array
, t01
);
2367 if (useBorderColor
& (I1BIT
| J1BIT
)) {
2368 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2371 img
->FetchTexelc(img
, i1
, j1
, array
, t11
);
2374 /* trilinear interpolation of samples */
2377 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
2384 sample_2d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2385 const struct gl_texture_object
*tObj
,
2386 GLuint n
, const GLfloat texcoord
[][4],
2387 const GLfloat lambda
[], GLchan rgba
[][4] )
2390 for (i
= 0; i
< n
; i
++) {
2391 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2392 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2399 sample_2d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2400 const struct gl_texture_object
*tObj
,
2401 GLuint n
, const GLfloat texcoord
[][4],
2402 const GLfloat lambda
[], GLchan rgba
[][4])
2405 ASSERT(lambda
!= NULL
);
2406 for (i
= 0; i
< n
; i
++) {
2407 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2408 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2409 texcoord
[i
], rgba
[i
]);
2415 sample_2d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2416 const struct gl_texture_object
*tObj
,
2417 GLuint n
, const GLfloat texcoord
[][4],
2418 const GLfloat lambda
[], GLchan rgba
[][4])
2421 ASSERT(lambda
!= NULL
);
2422 for (i
= 0; i
< n
; i
++) {
2423 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2424 if (level
>= tObj
->_MaxLevel
) {
2425 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2426 texcoord
[i
], rgba
[i
]);
2429 GLchan t0
[4], t1
[4]; /* texels */
2430 const GLfloat f
= FRAC(lambda
[i
]);
2431 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2432 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2433 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2440 sample_2d_array_linear_mipmap_linear(GLcontext
*ctx
,
2441 const struct gl_texture_object
*tObj
,
2442 GLuint n
, const GLfloat texcoord
[][4],
2443 const GLfloat lambda
[], GLchan rgba
[][4])
2446 ASSERT(lambda
!= NULL
);
2447 for (i
= 0; i
< n
; i
++) {
2448 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2449 if (level
>= tObj
->_MaxLevel
) {
2450 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2451 texcoord
[i
], rgba
[i
]);
2454 GLchan t0
[4], t1
[4]; /* texels */
2455 const GLfloat f
= FRAC(lambda
[i
]);
2456 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2457 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2458 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2465 sample_nearest_2d_array(GLcontext
*ctx
,
2466 const struct gl_texture_object
*tObj
, GLuint n
,
2467 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2471 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2474 sample_2d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2481 sample_linear_2d_array(GLcontext
*ctx
,
2482 const struct gl_texture_object
*tObj
, GLuint n
,
2483 const GLfloat texcoords
[][4],
2484 const GLfloat lambda
[], GLchan rgba
[][4])
2487 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2490 sample_2d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2496 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
2497 * return a texture sample.
2500 sample_lambda_2d_array(GLcontext
*ctx
,
2501 const struct gl_texture_object
*tObj
, GLuint n
,
2502 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2505 GLuint minStart
, minEnd
; /* texels with minification */
2506 GLuint magStart
, magEnd
; /* texels with magnification */
2509 ASSERT(lambda
!= NULL
);
2510 compute_min_mag_ranges(tObj
, n
, lambda
,
2511 &minStart
, &minEnd
, &magStart
, &magEnd
);
2513 if (minStart
< minEnd
) {
2514 /* do the minified texels */
2515 GLuint m
= minEnd
- minStart
;
2516 switch (tObj
->MinFilter
) {
2518 for (i
= minStart
; i
< minEnd
; i
++)
2519 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2520 texcoords
[i
], rgba
[i
]);
2523 for (i
= minStart
; i
< minEnd
; i
++)
2524 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2525 texcoords
[i
], rgba
[i
]);
2527 case GL_NEAREST_MIPMAP_NEAREST
:
2528 sample_2d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2529 lambda
+ minStart
, rgba
+ minStart
);
2531 case GL_LINEAR_MIPMAP_NEAREST
:
2532 sample_2d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2533 texcoords
+ minStart
,
2537 case GL_NEAREST_MIPMAP_LINEAR
:
2538 sample_2d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2539 lambda
+ minStart
, rgba
+ minStart
);
2541 case GL_LINEAR_MIPMAP_LINEAR
:
2542 sample_2d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2543 texcoords
+ minStart
,
2548 _mesa_problem(ctx
, "Bad min filter in sample_2d_array_texture");
2553 if (magStart
< magEnd
) {
2554 /* do the magnified texels */
2555 switch (tObj
->MagFilter
) {
2557 for (i
= magStart
; i
< magEnd
; i
++)
2558 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2559 texcoords
[i
], rgba
[i
]);
2562 for (i
= magStart
; i
< magEnd
; i
++)
2563 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2564 texcoords
[i
], rgba
[i
]);
2567 _mesa_problem(ctx
, "Bad mag filter in sample_2d_array_texture");
2576 /**********************************************************************/
2577 /* 1D Texture Array Sampling Functions */
2578 /**********************************************************************/
2581 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2584 sample_1d_array_nearest(GLcontext
*ctx
,
2585 const struct gl_texture_object
*tObj
,
2586 const struct gl_texture_image
*img
,
2587 const GLfloat texcoord
[4],
2590 const GLint width
= img
->Width2
; /* without border, power of two */
2591 const GLint height
= img
->Height
;
2596 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
2597 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2599 if (i
< 0 || i
>= (GLint
) img
->Width
||
2600 array
< 0 || array
>= (GLint
) img
->Height
) {
2601 /* Need this test for GL_CLAMP_TO_BORDER mode */
2602 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2605 img
->FetchTexelc(img
, i
, array
, 0, rgba
);
2612 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2615 sample_1d_array_linear(GLcontext
*ctx
,
2616 const struct gl_texture_object
*tObj
,
2617 const struct gl_texture_image
*img
,
2618 const GLfloat texcoord
[4],
2621 const GLint width
= img
->Width2
;
2622 const GLint height
= img
->Height
;
2625 GLbitfield useBorderColor
= 0x0;
2628 GLchan t0
[4], t1
[4];
2630 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
2631 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2638 /* check if sampling texture border color */
2639 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2640 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2643 if (array
< 0 || array
>= height
) useBorderColor
|= K0BIT
;
2646 if (useBorderColor
& (I0BIT
| K0BIT
)) {
2647 COPY_CHAN4(t0
, tObj
->_BorderChan
);
2650 img
->FetchTexelc(img
, i0
, array
, 0, t0
);
2652 if (useBorderColor
& (I1BIT
| K0BIT
)) {
2653 COPY_CHAN4(t1
, tObj
->_BorderChan
);
2656 img
->FetchTexelc(img
, i1
, array
, 0, t1
);
2659 /* bilinear interpolation of samples */
2661 lerp_rgba(rgba
, a
, t0
, t1
);
2667 sample_1d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2668 const struct gl_texture_object
*tObj
,
2669 GLuint n
, const GLfloat texcoord
[][4],
2670 const GLfloat lambda
[], GLchan rgba
[][4] )
2673 for (i
= 0; i
< n
; i
++) {
2674 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2675 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2682 sample_1d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2683 const struct gl_texture_object
*tObj
,
2684 GLuint n
, const GLfloat texcoord
[][4],
2685 const GLfloat lambda
[], GLchan rgba
[][4])
2688 ASSERT(lambda
!= NULL
);
2689 for (i
= 0; i
< n
; i
++) {
2690 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2691 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2692 texcoord
[i
], rgba
[i
]);
2698 sample_1d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2699 const struct gl_texture_object
*tObj
,
2700 GLuint n
, const GLfloat texcoord
[][4],
2701 const GLfloat lambda
[], GLchan rgba
[][4])
2704 ASSERT(lambda
!= NULL
);
2705 for (i
= 0; i
< n
; i
++) {
2706 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2707 if (level
>= tObj
->_MaxLevel
) {
2708 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2709 texcoord
[i
], rgba
[i
]);
2712 GLchan t0
[4], t1
[4]; /* texels */
2713 const GLfloat f
= FRAC(lambda
[i
]);
2714 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2715 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2716 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2723 sample_1d_array_linear_mipmap_linear(GLcontext
*ctx
,
2724 const struct gl_texture_object
*tObj
,
2725 GLuint n
, const GLfloat texcoord
[][4],
2726 const GLfloat lambda
[], GLchan rgba
[][4])
2729 ASSERT(lambda
!= NULL
);
2730 for (i
= 0; i
< n
; i
++) {
2731 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2732 if (level
>= tObj
->_MaxLevel
) {
2733 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2734 texcoord
[i
], rgba
[i
]);
2737 GLchan t0
[4], t1
[4]; /* texels */
2738 const GLfloat f
= FRAC(lambda
[i
]);
2739 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2740 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2741 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2748 sample_nearest_1d_array(GLcontext
*ctx
,
2749 const struct gl_texture_object
*tObj
, GLuint n
,
2750 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2754 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2757 sample_1d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2764 sample_linear_1d_array(GLcontext
*ctx
,
2765 const struct gl_texture_object
*tObj
, GLuint n
,
2766 const GLfloat texcoords
[][4],
2767 const GLfloat lambda
[], GLchan rgba
[][4])
2770 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2773 sample_1d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2779 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
2780 * return a texture sample.
2783 sample_lambda_1d_array(GLcontext
*ctx
,
2784 const struct gl_texture_object
*tObj
, GLuint n
,
2785 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2788 GLuint minStart
, minEnd
; /* texels with minification */
2789 GLuint magStart
, magEnd
; /* texels with magnification */
2792 ASSERT(lambda
!= NULL
);
2793 compute_min_mag_ranges(tObj
, n
, lambda
,
2794 &minStart
, &minEnd
, &magStart
, &magEnd
);
2796 if (minStart
< minEnd
) {
2797 /* do the minified texels */
2798 GLuint m
= minEnd
- minStart
;
2799 switch (tObj
->MinFilter
) {
2801 for (i
= minStart
; i
< minEnd
; i
++)
2802 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2803 texcoords
[i
], rgba
[i
]);
2806 for (i
= minStart
; i
< minEnd
; i
++)
2807 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2808 texcoords
[i
], rgba
[i
]);
2810 case GL_NEAREST_MIPMAP_NEAREST
:
2811 sample_1d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2812 lambda
+ minStart
, rgba
+ minStart
);
2814 case GL_LINEAR_MIPMAP_NEAREST
:
2815 sample_1d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2816 texcoords
+ minStart
,
2820 case GL_NEAREST_MIPMAP_LINEAR
:
2821 sample_1d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2822 lambda
+ minStart
, rgba
+ minStart
);
2824 case GL_LINEAR_MIPMAP_LINEAR
:
2825 sample_1d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2826 texcoords
+ minStart
,
2831 _mesa_problem(ctx
, "Bad min filter in sample_1d_array_texture");
2836 if (magStart
< magEnd
) {
2837 /* do the magnified texels */
2838 switch (tObj
->MagFilter
) {
2840 for (i
= magStart
; i
< magEnd
; i
++)
2841 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2842 texcoords
[i
], rgba
[i
]);
2845 for (i
= magStart
; i
< magEnd
; i
++)
2846 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2847 texcoords
[i
], rgba
[i
]);
2850 _mesa_problem(ctx
, "Bad mag filter in sample_1d_array_texture");
2860 * Sample a shadow/depth texture.
2863 sample_depth_texture( GLcontext
*ctx
,
2864 const struct gl_texture_object
*tObj
, GLuint n
,
2865 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2868 const GLint baseLevel
= tObj
->BaseLevel
;
2869 const struct gl_texture_image
*img
= tObj
->Image
[0][baseLevel
];
2870 const GLint width
= img
->Width
;
2871 const GLint height
= img
->Height
;
2872 const GLint depth
= img
->Depth
;
2873 const GLuint compare_coord
= (tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
)
2881 ASSERT(img
->TexFormat
->BaseFormat
== GL_DEPTH_COMPONENT
||
2882 img
->TexFormat
->BaseFormat
== GL_DEPTH_STENCIL_EXT
);
2884 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
2885 tObj
->Target
== GL_TEXTURE_2D
||
2886 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
||
2887 tObj
->Target
== GL_TEXTURE_1D_ARRAY_EXT
||
2888 tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
);
2890 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2892 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2894 function
= tObj
->_Function
;
2895 if (tObj
->MagFilter
== GL_NEAREST
) {
2897 for (i
= 0; i
< n
; i
++) {
2898 GLfloat depthSample
;
2899 GLint col
, row
, slice
;
2901 switch (tObj
->Target
) {
2902 case GL_TEXTURE_RECTANGLE_ARB
:
2903 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2904 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2909 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2916 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2918 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoords
[i
][1],
2923 case GL_TEXTURE_1D_ARRAY_EXT
:
2924 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2926 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2929 case GL_TEXTURE_2D_ARRAY_EXT
:
2930 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2932 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoords
[i
][1],
2934 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2938 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
&&
2939 slice
>= 0 && slice
< depth
) {
2940 img
->FetchTexelf(img
, col
, row
, slice
, &depthSample
);
2943 depthSample
= tObj
->BorderColor
[0];
2948 result
= (texcoords
[i
][compare_coord
] <= depthSample
) ? CHAN_MAX
: ambient
;
2951 result
= (texcoords
[i
][compare_coord
] >= depthSample
) ? CHAN_MAX
: ambient
;
2954 result
= (texcoords
[i
][compare_coord
] < depthSample
) ? CHAN_MAX
: ambient
;
2957 result
= (texcoords
[i
][compare_coord
] > depthSample
) ? CHAN_MAX
: ambient
;
2960 result
= (texcoords
[i
][compare_coord
] == depthSample
) ? CHAN_MAX
: ambient
;
2963 result
= (texcoords
[i
][compare_coord
] != depthSample
) ? CHAN_MAX
: ambient
;
2972 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2975 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2979 switch (tObj
->DepthMode
) {
2981 texel
[i
][RCOMP
] = result
;
2982 texel
[i
][GCOMP
] = result
;
2983 texel
[i
][BCOMP
] = result
;
2984 texel
[i
][ACOMP
] = CHAN_MAX
;
2987 texel
[i
][RCOMP
] = result
;
2988 texel
[i
][GCOMP
] = result
;
2989 texel
[i
][BCOMP
] = result
;
2990 texel
[i
][ACOMP
] = result
;
2993 texel
[i
][RCOMP
] = 0;
2994 texel
[i
][GCOMP
] = 0;
2995 texel
[i
][BCOMP
] = 0;
2996 texel
[i
][ACOMP
] = result
;
2999 _mesa_problem(ctx
, "Bad depth texture mode");
3005 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
3006 for (i
= 0; i
< n
; i
++) {
3007 GLfloat depth00
, depth01
, depth10
, depth11
;
3008 GLint i0
, i1
, j0
, j1
;
3011 GLuint useBorderTexel
;
3013 switch (tObj
->Target
) {
3014 case GL_TEXTURE_RECTANGLE_ARB
:
3015 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0],
3017 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1],
3024 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3026 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoords
[i
][1],
3031 case GL_TEXTURE_1D_ARRAY_EXT
:
3032 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3034 j0
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
3038 case GL_TEXTURE_2D_ARRAY_EXT
:
3039 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3041 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoords
[i
][1],
3043 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
3051 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3057 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
3058 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
3059 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
3060 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
3063 if (slice
< 0 || slice
>= (GLint
) depth
) {
3064 depth00
= tObj
->BorderColor
[0];
3065 depth01
= tObj
->BorderColor
[0];
3066 depth10
= tObj
->BorderColor
[0];
3067 depth11
= tObj
->BorderColor
[0];
3070 /* get four depth samples from the texture */
3071 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
3072 depth00
= tObj
->BorderColor
[0];
3075 img
->FetchTexelf(img
, i0
, j0
, slice
, &depth00
);
3077 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
3078 depth10
= tObj
->BorderColor
[0];
3081 img
->FetchTexelf(img
, i1
, j0
, slice
, &depth10
);
3084 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3085 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
3086 depth01
= tObj
->BorderColor
[0];
3089 img
->FetchTexelf(img
, i0
, j1
, slice
, &depth01
);
3091 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
3092 depth11
= tObj
->BorderColor
[0];
3095 img
->FetchTexelf(img
, i1
, j1
, slice
, &depth11
);
3105 /* compute a single weighted depth sample and do one comparison */
3106 const GLfloat a
= FRAC(u
+ 1.0F
);
3107 const GLfloat b
= FRAC(v
+ 1.0F
);
3108 const GLfloat depthSample
3109 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3110 if ((depthSample
<= texcoords
[i
][compare_coord
] && function
== GL_LEQUAL
) ||
3111 (depthSample
>= texcoords
[i
][compare_coord
] && function
== GL_GEQUAL
)) {
3119 /* Do four depth/R comparisons and compute a weighted result.
3120 * If this touches on somebody's I.P., I'll remove this code
3123 const GLfloat d
= (CHAN_MAXF
- (GLfloat
) ambient
) * 0.25F
;
3124 GLfloat luminance
= CHAN_MAXF
;
3128 if (depth00
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3129 if (depth01
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3130 if (depth10
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3131 if (depth11
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3132 result
= (GLchan
) luminance
;
3135 if (depth00
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3136 if (depth01
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3137 if (depth10
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3138 if (depth11
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3139 result
= (GLchan
) luminance
;
3142 if (depth00
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3143 if (depth01
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3144 if (depth10
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3145 if (depth11
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3146 result
= (GLchan
) luminance
;
3149 if (depth00
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3150 if (depth01
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3151 if (depth10
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3152 if (depth11
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3153 result
= (GLchan
) luminance
;
3156 if (depth00
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3157 if (depth01
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3158 if (depth10
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3159 if (depth11
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3160 result
= (GLchan
) luminance
;
3163 if (depth00
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3164 if (depth01
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3165 if (depth10
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3166 if (depth11
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3167 result
= (GLchan
) luminance
;
3176 /* ordinary bilinear filtering */
3178 const GLfloat a
= FRAC(u
+ 1.0F
);
3179 const GLfloat b
= FRAC(v
+ 1.0F
);
3180 const GLfloat depthSample
3181 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3182 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
3186 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
3191 switch (tObj
->DepthMode
) {
3193 texel
[i
][RCOMP
] = result
;
3194 texel
[i
][GCOMP
] = result
;
3195 texel
[i
][BCOMP
] = result
;
3196 texel
[i
][ACOMP
] = CHAN_MAX
;
3199 texel
[i
][RCOMP
] = result
;
3200 texel
[i
][GCOMP
] = result
;
3201 texel
[i
][BCOMP
] = result
;
3202 texel
[i
][ACOMP
] = result
;
3205 texel
[i
][RCOMP
] = 0;
3206 texel
[i
][GCOMP
] = 0;
3207 texel
[i
][BCOMP
] = 0;
3208 texel
[i
][ACOMP
] = result
;
3211 _mesa_problem(ctx
, "Bad depth texture mode");
3220 * Experimental depth texture sampling function.
3223 sample_depth_texture2(const GLcontext
*ctx
,
3224 const struct gl_texture_unit
*texUnit
,
3225 GLuint n
, const GLfloat texcoords
[][4],
3228 const struct gl_texture_object
*texObj
= texUnit
->_Current
;
3229 const GLint baseLevel
= texObj
->BaseLevel
;
3230 const struct gl_texture_image
*texImage
= texObj
->Image
[0][baseLevel
];
3231 const GLuint width
= texImage
->Width
;
3232 const GLuint height
= texImage
->Height
;
3234 GLboolean lequal
, gequal
;
3236 if (texObj
->Target
!= GL_TEXTURE_2D
) {
3237 _mesa_problem(ctx
, "only 2-D depth textures supported at this time");
3241 if (texObj
->MinFilter
!= texObj
->MagFilter
) {
3242 _mesa_problem(ctx
, "mipmapped depth textures not supported at this time");
3246 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
3247 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
3248 * isn't a depth texture.
3250 if (texImage
->TexFormat
->BaseFormat
!= GL_DEPTH_COMPONENT
) {
3251 _mesa_problem(ctx
,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
3255 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
3257 if (texObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
3268 for (i
= 0; i
< n
; i
++) {
3270 GLint col
, row
, ii
, jj
, imin
, imax
, jmin
, jmax
, samples
, count
;
3273 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapS
, texcoords
[i
][0],
3275 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapT
, texcoords
[i
][1],
3283 if (imin
< 0) imin
= 0;
3284 if (imax
>= width
) imax
= width
- 1;
3285 if (jmin
< 0) jmin
= 0;
3286 if (jmax
>= height
) jmax
= height
- 1;
3288 samples
= (imax
- imin
+ 1) * (jmax
- jmin
+ 1);
3290 for (jj
= jmin
; jj
<= jmax
; jj
++) {
3291 for (ii
= imin
; ii
<= imax
; ii
++) {
3292 GLfloat depthSample
;
3293 texImage
->FetchTexelf(texImage
, ii
, jj
, 0, &depthSample
);
3294 if ((depthSample
<= r
[i
] && lequal
) ||
3295 (depthSample
>= r
[i
] && gequal
)) {
3301 w
= (GLfloat
) count
/ (GLfloat
) samples
;
3302 w
= CHAN_MAXF
- w
* (CHAN_MAXF
- (GLfloat
) ambient
);
3305 texel
[i
][RCOMP
] = lum
;
3306 texel
[i
][GCOMP
] = lum
;
3307 texel
[i
][BCOMP
] = lum
;
3308 texel
[i
][ACOMP
] = CHAN_MAX
;
3316 * We use this function when a texture object is in an "incomplete" state.
3317 * When a fragment program attempts to sample an incomplete texture we
3318 * return black (see issue 23 in GL_ARB_fragment_program spec).
3319 * Note: fragment programs don't observe the texture enable/disable flags.
3322 null_sample_func( GLcontext
*ctx
,
3323 const struct gl_texture_object
*tObj
, GLuint n
,
3324 const GLfloat texcoords
[][4], const GLfloat lambda
[],
3332 for (i
= 0; i
< n
; i
++) {
3336 rgba
[i
][ACOMP
] = CHAN_MAX
;
3342 * Choose the texture sampling function for the given texture object.
3345 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
3346 const struct gl_texture_object
*t
)
3348 if (!t
|| !t
->_Complete
) {
3349 return &null_sample_func
;
3352 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
3353 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->TexFormat
->BaseFormat
;
3355 switch (t
->Target
) {
3357 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3358 return &sample_depth_texture
;
3360 else if (needLambda
) {
3361 return &sample_lambda_1d
;
3363 else if (t
->MinFilter
== GL_LINEAR
) {
3364 return &sample_linear_1d
;
3367 ASSERT(t
->MinFilter
== GL_NEAREST
);
3368 return &sample_nearest_1d
;
3371 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3372 return &sample_depth_texture
;
3374 else if (needLambda
) {
3375 return &sample_lambda_2d
;
3377 else if (t
->MinFilter
== GL_LINEAR
) {
3378 return &sample_linear_2d
;
3381 /* check for a few optimized cases */
3382 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
3383 ASSERT(t
->MinFilter
== GL_NEAREST
);
3384 if (t
->WrapS
== GL_REPEAT
&&
3385 t
->WrapT
== GL_REPEAT
&&
3386 img
->_IsPowerOfTwo
&&
3388 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGB
) {
3389 return &opt_sample_rgb_2d
;
3391 else if (t
->WrapS
== GL_REPEAT
&&
3392 t
->WrapT
== GL_REPEAT
&&
3393 img
->_IsPowerOfTwo
&&
3395 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGBA
) {
3396 return &opt_sample_rgba_2d
;
3399 return &sample_nearest_2d
;
3404 return &sample_lambda_3d
;
3406 else if (t
->MinFilter
== GL_LINEAR
) {
3407 return &sample_linear_3d
;
3410 ASSERT(t
->MinFilter
== GL_NEAREST
);
3411 return &sample_nearest_3d
;
3413 case GL_TEXTURE_CUBE_MAP
:
3415 return &sample_lambda_cube
;
3417 else if (t
->MinFilter
== GL_LINEAR
) {
3418 return &sample_linear_cube
;
3421 ASSERT(t
->MinFilter
== GL_NEAREST
);
3422 return &sample_nearest_cube
;
3424 case GL_TEXTURE_RECTANGLE_NV
:
3425 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3426 return &sample_depth_texture
;
3428 else if (needLambda
) {
3429 return &sample_lambda_rect
;
3431 else if (t
->MinFilter
== GL_LINEAR
) {
3432 return &sample_linear_rect
;
3435 ASSERT(t
->MinFilter
== GL_NEAREST
);
3436 return &sample_nearest_rect
;
3438 case GL_TEXTURE_1D_ARRAY_EXT
:
3440 return &sample_lambda_1d_array
;
3442 else if (t
->MinFilter
== GL_LINEAR
) {
3443 return &sample_linear_1d_array
;
3446 ASSERT(t
->MinFilter
== GL_NEAREST
);
3447 return &sample_nearest_1d_array
;
3449 case GL_TEXTURE_2D_ARRAY_EXT
:
3451 return &sample_lambda_2d_array
;
3453 else if (t
->MinFilter
== GL_LINEAR
) {
3454 return &sample_linear_2d_array
;
3457 ASSERT(t
->MinFilter
== GL_NEAREST
);
3458 return &sample_nearest_2d_array
;
3462 "invalid target in _swrast_choose_texture_sample_func");
3463 return &null_sample_func
;