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 "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"); \
350 * Used to compute texel location for nearest sampling.
352 #define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \
354 switch (wrapMode) { \
356 /* s limited to [0,1) */ \
357 /* i limited to [0,size-1] */ \
358 I = IFLOOR(S * SIZE); \
359 if (img->_IsPowerOfTwo) \
362 I = REMAINDER(I, SIZE); \
364 case GL_CLAMP_TO_EDGE: \
366 /* s limited to [min,max] */ \
367 /* i limited to [0, size-1] */ \
368 const GLfloat min = 1.0F / (2.0F * SIZE); \
369 const GLfloat max = 1.0F - min; \
375 I = IFLOOR(S * SIZE); \
378 case GL_CLAMP_TO_BORDER: \
380 /* s limited to [min,max] */ \
381 /* i limited to [-1, size] */ \
382 const GLfloat min = -1.0F / (2.0F * SIZE); \
383 const GLfloat max = 1.0F - min; \
389 I = IFLOOR(S * SIZE); \
392 case GL_MIRRORED_REPEAT: \
394 const GLfloat min = 1.0F / (2.0F * SIZE); \
395 const GLfloat max = 1.0F - min; \
396 const GLint flr = IFLOOR(S); \
399 u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
401 u = S - (GLfloat) flr; /* flr is even */ \
407 I = IFLOOR(u * SIZE); \
410 case GL_MIRROR_CLAMP_EXT: \
412 /* s limited to [0,1] */ \
413 /* i limited to [0,size-1] */ \
414 const GLfloat u = FABSF(S); \
417 else if (u >= 1.0F) \
420 I = IFLOOR(u * SIZE); \
423 case GL_MIRROR_CLAMP_TO_EDGE_EXT: \
425 /* s limited to [min,max] */ \
426 /* i limited to [0, size-1] */ \
427 const GLfloat min = 1.0F / (2.0F * SIZE); \
428 const GLfloat max = 1.0F - min; \
429 const GLfloat u = FABSF(S); \
435 I = IFLOOR(u * SIZE); \
438 case GL_MIRROR_CLAMP_TO_BORDER_EXT: \
440 /* s limited to [min,max] */ \
441 /* i limited to [0, size-1] */ \
442 const GLfloat min = -1.0F / (2.0F * SIZE); \
443 const GLfloat max = 1.0F - min; \
444 const GLfloat u = FABSF(S); \
450 I = IFLOOR(u * SIZE); \
454 /* s limited to [0,1] */ \
455 /* i limited to [0,size-1] */ \
458 else if (S >= 1.0F) \
461 I = IFLOOR(S * SIZE); \
464 _mesa_problem(ctx, "Bad wrap mode"); \
469 /* Power of two image sizes only */
470 #define COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(S, U, SIZE, I0, I1) \
472 U = S * SIZE - 0.5F; \
473 I0 = IFLOOR(U) & (SIZE - 1); \
474 I1 = (I0 + 1) & (SIZE - 1); \
479 * For linear interpolation between mipmap levels N and N+1, this function
483 linear_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
486 return tObj
->BaseLevel
;
487 else if (lambda
> tObj
->_MaxLambda
)
488 return (GLint
) (tObj
->BaseLevel
+ tObj
->_MaxLambda
);
490 return (GLint
) (tObj
->BaseLevel
+ lambda
);
495 * Compute the nearest mipmap level to take texels from.
498 nearest_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
504 else if (lambda
> tObj
->_MaxLambda
+ 0.4999F
)
505 l
= tObj
->_MaxLambda
+ 0.4999F
;
508 level
= (GLint
) (tObj
->BaseLevel
+ l
+ 0.5F
);
509 if (level
> tObj
->_MaxLevel
)
510 level
= tObj
->_MaxLevel
;
517 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
518 * see 1-pixel bands of improperly weighted linear-filtered textures.
519 * The tests/texwrap.c demo is a good test.
520 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
521 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
523 #define FRAC(f) ((f) - IFLOOR(f))
528 * Bitflags for texture border color sampling.
540 * The lambda[] array values are always monotonic. Either the whole span
541 * will be minified, magnified, or split between the two. This function
542 * determines the subranges in [0, n-1] that are to be minified or magnified.
545 compute_min_mag_ranges(const struct gl_texture_object
*tObj
,
546 GLuint n
, const GLfloat lambda
[],
547 GLuint
*minStart
, GLuint
*minEnd
,
548 GLuint
*magStart
, GLuint
*magEnd
)
550 GLfloat minMagThresh
;
552 /* we shouldn't be here if minfilter == magfilter */
553 ASSERT(tObj
->MinFilter
!= tObj
->MagFilter
);
555 /* This bit comes from the OpenGL spec: */
556 if (tObj
->MagFilter
== GL_LINEAR
557 && (tObj
->MinFilter
== GL_NEAREST_MIPMAP_NEAREST
||
558 tObj
->MinFilter
== GL_NEAREST_MIPMAP_LINEAR
)) {
566 /* DEBUG CODE: Verify that lambda[] is monotonic.
567 * We can't really use this because the inaccuracy in the LOG2 function
568 * causes this test to fail, yet the resulting texturing is correct.
572 printf("lambda delta = %g\n", lambda
[0] - lambda
[n
-1]);
573 if (lambda
[0] >= lambda
[n
-1]) { /* decreasing */
574 for (i
= 0; i
< n
- 1; i
++) {
575 ASSERT((GLint
) (lambda
[i
] * 10) >= (GLint
) (lambda
[i
+1] * 10));
578 else { /* increasing */
579 for (i
= 0; i
< n
- 1; i
++) {
580 ASSERT((GLint
) (lambda
[i
] * 10) <= (GLint
) (lambda
[i
+1] * 10));
586 if (lambda
[0] <= minMagThresh
&& (n
<= 1 || lambda
[n
-1] <= minMagThresh
)) {
587 /* magnification for whole span */
590 *minStart
= *minEnd
= 0;
592 else if (lambda
[0] > minMagThresh
&& (n
<=1 || lambda
[n
-1] > minMagThresh
)) {
593 /* minification for whole span */
596 *magStart
= *magEnd
= 0;
599 /* a mix of minification and magnification */
601 if (lambda
[0] > minMagThresh
) {
602 /* start with minification */
603 for (i
= 1; i
< n
; i
++) {
604 if (lambda
[i
] <= minMagThresh
)
613 /* start with magnification */
614 for (i
= 1; i
< n
; i
++) {
615 if (lambda
[i
] > minMagThresh
)
626 /* Verify the min/mag Start/End values
627 * We don't use this either (see above)
631 for (i
= 0; i
< n
; i
++) {
632 if (lambda
[i
] > minMagThresh
) {
634 ASSERT(i
>= *minStart
);
639 ASSERT(i
>= *magStart
);
648 /**********************************************************************/
649 /* 1-D Texture Sampling Functions */
650 /**********************************************************************/
653 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
656 sample_1d_nearest(GLcontext
*ctx
,
657 const struct gl_texture_object
*tObj
,
658 const struct gl_texture_image
*img
,
659 const GLfloat texcoord
[4], GLchan rgba
[4])
661 const GLint width
= img
->Width2
; /* without border, power of two */
663 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
664 /* skip over the border, if any */
666 if (i
< 0 || i
>= (GLint
) img
->Width
) {
667 /* Need this test for GL_CLAMP_TO_BORDER mode */
668 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
671 img
->FetchTexelc(img
, i
, 0, 0, rgba
);
677 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
680 sample_1d_linear(GLcontext
*ctx
,
681 const struct gl_texture_object
*tObj
,
682 const struct gl_texture_image
*img
,
683 const GLfloat texcoord
[4], GLchan rgba
[4])
685 const GLint width
= img
->Width2
;
688 GLbitfield useBorderColor
= 0x0;
690 GLchan t0
[4], t1
[4]; /* texels */
692 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
699 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
700 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
703 /* fetch texel colors */
704 if (useBorderColor
& I0BIT
) {
705 COPY_CHAN4(t0
, tObj
->_BorderChan
);
708 img
->FetchTexelc(img
, i0
, 0, 0, t0
);
710 if (useBorderColor
& I1BIT
) {
711 COPY_CHAN4(t1
, tObj
->_BorderChan
);
714 img
->FetchTexelc(img
, i1
, 0, 0, t1
);
718 lerp_rgba(rgba
, a
, t0
, t1
);
723 sample_1d_nearest_mipmap_nearest(GLcontext
*ctx
,
724 const struct gl_texture_object
*tObj
,
725 GLuint n
, const GLfloat texcoord
[][4],
726 const GLfloat lambda
[], GLchan rgba
[][4])
729 ASSERT(lambda
!= NULL
);
730 for (i
= 0; i
< n
; i
++) {
731 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
732 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
738 sample_1d_linear_mipmap_nearest(GLcontext
*ctx
,
739 const struct gl_texture_object
*tObj
,
740 GLuint n
, const GLfloat texcoord
[][4],
741 const GLfloat lambda
[], GLchan rgba
[][4])
744 ASSERT(lambda
!= NULL
);
745 for (i
= 0; i
< n
; i
++) {
746 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
747 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
753 sample_1d_nearest_mipmap_linear(GLcontext
*ctx
,
754 const struct gl_texture_object
*tObj
,
755 GLuint n
, const GLfloat texcoord
[][4],
756 const GLfloat lambda
[], GLchan rgba
[][4])
759 ASSERT(lambda
!= NULL
);
760 for (i
= 0; i
< n
; i
++) {
761 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
762 if (level
>= tObj
->_MaxLevel
) {
763 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
764 texcoord
[i
], rgba
[i
]);
768 const GLfloat f
= FRAC(lambda
[i
]);
769 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
770 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
771 lerp_rgba(rgba
[i
], f
, t0
, t1
);
779 sample_1d_linear_mipmap_linear(GLcontext
*ctx
,
780 const struct gl_texture_object
*tObj
,
781 GLuint n
, const GLfloat texcoord
[][4],
782 const GLfloat lambda
[], GLchan rgba
[][4])
785 ASSERT(lambda
!= NULL
);
786 for (i
= 0; i
< n
; i
++) {
787 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
788 if (level
>= tObj
->_MaxLevel
) {
789 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
790 texcoord
[i
], rgba
[i
]);
794 const GLfloat f
= FRAC(lambda
[i
]);
795 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
796 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
797 lerp_rgba(rgba
[i
], f
, t0
, t1
);
805 sample_nearest_1d( GLcontext
*ctx
,
806 const struct gl_texture_object
*tObj
, GLuint n
,
807 const GLfloat texcoords
[][4], const GLfloat lambda
[],
811 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
814 sample_1d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
821 sample_linear_1d( GLcontext
*ctx
,
822 const struct gl_texture_object
*tObj
, GLuint n
,
823 const GLfloat texcoords
[][4], const GLfloat lambda
[],
827 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
830 sample_1d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
836 * Given an (s) texture coordinate and lambda (level of detail) value,
837 * return a texture sample.
841 sample_lambda_1d( GLcontext
*ctx
,
842 const struct gl_texture_object
*tObj
, GLuint n
,
843 const GLfloat texcoords
[][4],
844 const GLfloat lambda
[], GLchan rgba
[][4] )
846 GLuint minStart
, minEnd
; /* texels with minification */
847 GLuint magStart
, magEnd
; /* texels with magnification */
850 ASSERT(lambda
!= NULL
);
851 compute_min_mag_ranges(tObj
, n
, lambda
,
852 &minStart
, &minEnd
, &magStart
, &magEnd
);
854 if (minStart
< minEnd
) {
855 /* do the minified texels */
856 const GLuint m
= minEnd
- minStart
;
857 switch (tObj
->MinFilter
) {
859 for (i
= minStart
; i
< minEnd
; i
++)
860 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
861 texcoords
[i
], rgba
[i
]);
864 for (i
= minStart
; i
< minEnd
; i
++)
865 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
866 texcoords
[i
], rgba
[i
]);
868 case GL_NEAREST_MIPMAP_NEAREST
:
869 sample_1d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
870 lambda
+ minStart
, rgba
+ minStart
);
872 case GL_LINEAR_MIPMAP_NEAREST
:
873 sample_1d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
874 lambda
+ minStart
, rgba
+ minStart
);
876 case GL_NEAREST_MIPMAP_LINEAR
:
877 sample_1d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
878 lambda
+ minStart
, rgba
+ minStart
);
880 case GL_LINEAR_MIPMAP_LINEAR
:
881 sample_1d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
882 lambda
+ minStart
, rgba
+ minStart
);
885 _mesa_problem(ctx
, "Bad min filter in sample_1d_texture");
890 if (magStart
< magEnd
) {
891 /* do the magnified texels */
892 switch (tObj
->MagFilter
) {
894 for (i
= magStart
; i
< magEnd
; i
++)
895 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
896 texcoords
[i
], rgba
[i
]);
899 for (i
= magStart
; i
< magEnd
; i
++)
900 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
901 texcoords
[i
], rgba
[i
]);
904 _mesa_problem(ctx
, "Bad mag filter in sample_1d_texture");
911 /**********************************************************************/
912 /* 2-D Texture Sampling Functions */
913 /**********************************************************************/
917 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
920 sample_2d_nearest(GLcontext
*ctx
,
921 const struct gl_texture_object
*tObj
,
922 const struct gl_texture_image
*img
,
923 const GLfloat texcoord
[4],
926 const GLint width
= img
->Width2
; /* without border, power of two */
927 const GLint height
= img
->Height2
; /* without border, power of two */
931 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
932 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
934 /* skip over the border, if any */
938 if (i
< 0 || i
>= (GLint
) img
->Width
|| j
< 0 || j
>= (GLint
) img
->Height
) {
939 /* Need this test for GL_CLAMP_TO_BORDER mode */
940 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
943 img
->FetchTexelc(img
, i
, j
, 0, rgba
);
950 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
951 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
954 sample_2d_linear(GLcontext
*ctx
,
955 const struct gl_texture_object
*tObj
,
956 const struct gl_texture_image
*img
,
957 const GLfloat texcoord
[4],
960 const GLint width
= img
->Width2
;
961 const GLint height
= img
->Height2
;
962 GLint i0
, j0
, i1
, j1
;
963 GLbitfield useBorderColor
= 0x0;
966 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
968 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
969 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
978 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
979 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
980 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
981 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
984 /* fetch four texel colors */
985 if (useBorderColor
& (I0BIT
| J0BIT
)) {
986 COPY_CHAN4(t00
, tObj
->_BorderChan
);
989 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
991 if (useBorderColor
& (I1BIT
| J0BIT
)) {
992 COPY_CHAN4(t10
, tObj
->_BorderChan
);
995 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
997 if (useBorderColor
& (I0BIT
| J1BIT
)) {
998 COPY_CHAN4(t01
, tObj
->_BorderChan
);
1001 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1003 if (useBorderColor
& (I1BIT
| J1BIT
)) {
1004 COPY_CHAN4(t11
, tObj
->_BorderChan
);
1007 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1012 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1017 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1018 * We don't have to worry about the texture border.
1021 sample_2d_linear_repeat(GLcontext
*ctx
,
1022 const struct gl_texture_object
*tObj
,
1023 const struct gl_texture_image
*img
,
1024 const GLfloat texcoord
[4],
1027 const GLint width
= img
->Width2
;
1028 const GLint height
= img
->Height2
;
1029 GLint i0
, j0
, i1
, j1
;
1032 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
1036 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1037 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1038 ASSERT(img
->Border
== 0);
1039 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
1040 ASSERT(img
->_IsPowerOfTwo
);
1042 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[0], u
, width
, i0
, i1
);
1043 COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord
[1], v
, height
, j0
, j1
);
1045 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
1046 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
1047 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1048 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1052 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1058 sample_2d_nearest_mipmap_nearest(GLcontext
*ctx
,
1059 const struct gl_texture_object
*tObj
,
1060 GLuint n
, const GLfloat texcoord
[][4],
1061 const GLfloat lambda
[], GLchan rgba
[][4])
1064 for (i
= 0; i
< n
; i
++) {
1065 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1066 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1073 sample_2d_linear_mipmap_nearest(GLcontext
*ctx
,
1074 const struct gl_texture_object
*tObj
,
1075 GLuint n
, const GLfloat texcoord
[][4],
1076 const GLfloat lambda
[], GLchan rgba
[][4])
1079 ASSERT(lambda
!= NULL
);
1080 for (i
= 0; i
< n
; i
++) {
1081 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1082 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1089 sample_2d_nearest_mipmap_linear(GLcontext
*ctx
,
1090 const struct gl_texture_object
*tObj
,
1091 GLuint n
, const GLfloat texcoord
[][4],
1092 const GLfloat lambda
[], GLchan rgba
[][4])
1095 ASSERT(lambda
!= NULL
);
1096 for (i
= 0; i
< n
; i
++) {
1097 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1098 if (level
>= tObj
->_MaxLevel
) {
1099 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1100 texcoord
[i
], rgba
[i
]);
1103 GLchan t0
[4], t1
[4]; /* texels */
1104 const GLfloat f
= FRAC(lambda
[i
]);
1105 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1106 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1107 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1114 /* Trilinear filtering */
1116 sample_2d_linear_mipmap_linear( GLcontext
*ctx
,
1117 const struct gl_texture_object
*tObj
,
1118 GLuint n
, const GLfloat texcoord
[][4],
1119 const GLfloat lambda
[], GLchan rgba
[][4] )
1122 ASSERT(lambda
!= NULL
);
1123 for (i
= 0; i
< n
; i
++) {
1124 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1125 if (level
>= tObj
->_MaxLevel
) {
1126 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1127 texcoord
[i
], rgba
[i
]);
1130 GLchan t0
[4], t1
[4]; /* texels */
1131 const GLfloat f
= FRAC(lambda
[i
]);
1132 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1133 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1134 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1141 sample_2d_linear_mipmap_linear_repeat( GLcontext
*ctx
,
1142 const struct gl_texture_object
*tObj
,
1143 GLuint n
, const GLfloat texcoord
[][4],
1144 const GLfloat lambda
[], GLchan rgba
[][4] )
1147 ASSERT(lambda
!= NULL
);
1148 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1149 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1150 for (i
= 0; i
< n
; i
++) {
1151 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1152 if (level
>= tObj
->_MaxLevel
) {
1153 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1154 texcoord
[i
], rgba
[i
]);
1157 GLchan t0
[4], t1
[4]; /* texels */
1158 const GLfloat f
= FRAC(lambda
[i
]);
1159 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1160 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1161 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1168 sample_nearest_2d( GLcontext
*ctx
,
1169 const struct gl_texture_object
*tObj
, GLuint n
,
1170 const GLfloat texcoords
[][4],
1171 const GLfloat lambda
[], GLchan rgba
[][4] )
1174 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1177 sample_2d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1184 sample_linear_2d( GLcontext
*ctx
,
1185 const struct gl_texture_object
*tObj
, GLuint n
,
1186 const GLfloat texcoords
[][4],
1187 const GLfloat lambda
[], GLchan rgba
[][4] )
1190 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1192 if (tObj
->WrapS
== GL_REPEAT
&&
1193 tObj
->WrapT
== GL_REPEAT
&&
1194 image
->_IsPowerOfTwo
&&
1195 image
->Border
== 0) {
1197 sample_2d_linear_repeat(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1202 sample_2d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1209 * Optimized 2-D texture sampling:
1210 * S and T wrap mode == GL_REPEAT
1211 * GL_NEAREST min/mag filter
1213 * RowStride == Width,
1217 opt_sample_rgb_2d( GLcontext
*ctx
,
1218 const struct gl_texture_object
*tObj
,
1219 GLuint n
, const GLfloat texcoords
[][4],
1220 const GLfloat lambda
[], GLchan rgba
[][4] )
1222 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1223 const GLfloat width
= (GLfloat
) img
->Width
;
1224 const GLfloat height
= (GLfloat
) img
->Height
;
1225 const GLint colMask
= img
->Width
- 1;
1226 const GLint rowMask
= img
->Height
- 1;
1227 const GLint shift
= img
->WidthLog2
;
1231 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1232 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1233 ASSERT(img
->Border
==0);
1234 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGB
);
1235 ASSERT(img
->_IsPowerOfTwo
);
1237 for (k
=0; k
<n
; k
++) {
1238 GLint i
= IFLOOR(texcoords
[k
][0] * width
) & colMask
;
1239 GLint j
= IFLOOR(texcoords
[k
][1] * height
) & rowMask
;
1240 GLint pos
= (j
<< shift
) | i
;
1241 GLchan
*texel
= ((GLchan
*) img
->Data
) + 3*pos
;
1242 rgba
[k
][RCOMP
] = texel
[0];
1243 rgba
[k
][GCOMP
] = texel
[1];
1244 rgba
[k
][BCOMP
] = texel
[2];
1250 * Optimized 2-D texture sampling:
1251 * S and T wrap mode == GL_REPEAT
1252 * GL_NEAREST min/mag filter
1254 * RowStride == Width,
1258 opt_sample_rgba_2d( GLcontext
*ctx
,
1259 const struct gl_texture_object
*tObj
,
1260 GLuint n
, const GLfloat texcoords
[][4],
1261 const GLfloat lambda
[], GLchan rgba
[][4] )
1263 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1264 const GLfloat width
= (GLfloat
) img
->Width
;
1265 const GLfloat height
= (GLfloat
) img
->Height
;
1266 const GLint colMask
= img
->Width
- 1;
1267 const GLint rowMask
= img
->Height
- 1;
1268 const GLint shift
= img
->WidthLog2
;
1272 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1273 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1274 ASSERT(img
->Border
==0);
1275 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGBA
);
1276 ASSERT(img
->_IsPowerOfTwo
);
1278 for (i
= 0; i
< n
; i
++) {
1279 const GLint col
= IFLOOR(texcoords
[i
][0] * width
) & colMask
;
1280 const GLint row
= IFLOOR(texcoords
[i
][1] * height
) & rowMask
;
1281 const GLint pos
= (row
<< shift
) | col
;
1282 const GLchan
*texel
= ((GLchan
*) img
->Data
) + (pos
<< 2); /* pos*4 */
1283 COPY_CHAN4(rgba
[i
], texel
);
1289 * Given an array of texture coordinate and lambda (level of detail)
1290 * values, return an array of texture sample.
1293 sample_lambda_2d( GLcontext
*ctx
,
1294 const struct gl_texture_object
*tObj
,
1295 GLuint n
, const GLfloat texcoords
[][4],
1296 const GLfloat lambda
[], GLchan rgba
[][4] )
1298 const struct gl_texture_image
*tImg
= tObj
->Image
[0][tObj
->BaseLevel
];
1299 GLuint minStart
, minEnd
; /* texels with minification */
1300 GLuint magStart
, magEnd
; /* texels with magnification */
1302 const GLboolean repeatNoBorderPOT
= (tObj
->WrapS
== GL_REPEAT
)
1303 && (tObj
->WrapT
== GL_REPEAT
)
1304 && (tImg
->Border
== 0 && (tImg
->Width
== tImg
->RowStride
))
1305 && (tImg
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
)
1306 && tImg
->_IsPowerOfTwo
;
1308 ASSERT(lambda
!= NULL
);
1309 compute_min_mag_ranges(tObj
, n
, lambda
,
1310 &minStart
, &minEnd
, &magStart
, &magEnd
);
1312 if (minStart
< minEnd
) {
1313 /* do the minified texels */
1314 const GLuint m
= minEnd
- minStart
;
1315 switch (tObj
->MinFilter
) {
1317 if (repeatNoBorderPOT
) {
1318 switch (tImg
->TexFormat
->MesaFormat
) {
1319 case MESA_FORMAT_RGB
:
1320 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1321 NULL
, rgba
+ minStart
);
1323 case MESA_FORMAT_RGBA
:
1324 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1325 NULL
, rgba
+ minStart
);
1328 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1329 NULL
, rgba
+ minStart
);
1333 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1334 NULL
, rgba
+ minStart
);
1338 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1339 NULL
, rgba
+ minStart
);
1341 case GL_NEAREST_MIPMAP_NEAREST
:
1342 sample_2d_nearest_mipmap_nearest(ctx
, tObj
, m
,
1343 texcoords
+ minStart
,
1344 lambda
+ minStart
, rgba
+ minStart
);
1346 case GL_LINEAR_MIPMAP_NEAREST
:
1347 sample_2d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1348 lambda
+ minStart
, rgba
+ minStart
);
1350 case GL_NEAREST_MIPMAP_LINEAR
:
1351 sample_2d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1352 lambda
+ minStart
, rgba
+ minStart
);
1354 case GL_LINEAR_MIPMAP_LINEAR
:
1355 if (repeatNoBorderPOT
)
1356 sample_2d_linear_mipmap_linear_repeat(ctx
, tObj
, m
,
1357 texcoords
+ minStart
, lambda
+ minStart
, rgba
+ minStart
);
1359 sample_2d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1360 lambda
+ minStart
, rgba
+ minStart
);
1363 _mesa_problem(ctx
, "Bad min filter in sample_2d_texture");
1368 if (magStart
< magEnd
) {
1369 /* do the magnified texels */
1370 const GLuint m
= magEnd
- magStart
;
1372 switch (tObj
->MagFilter
) {
1374 if (repeatNoBorderPOT
) {
1375 switch (tImg
->TexFormat
->MesaFormat
) {
1376 case MESA_FORMAT_RGB
:
1377 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1378 NULL
, rgba
+ magStart
);
1380 case MESA_FORMAT_RGBA
:
1381 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1382 NULL
, rgba
+ magStart
);
1385 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1386 NULL
, rgba
+ magStart
);
1390 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1391 NULL
, rgba
+ magStart
);
1395 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1396 NULL
, rgba
+ magStart
);
1399 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_2d");
1406 /**********************************************************************/
1407 /* 3-D Texture Sampling Functions */
1408 /**********************************************************************/
1411 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1414 sample_3d_nearest(GLcontext
*ctx
,
1415 const struct gl_texture_object
*tObj
,
1416 const struct gl_texture_image
*img
,
1417 const GLfloat texcoord
[4],
1420 const GLint width
= img
->Width2
; /* without border, power of two */
1421 const GLint height
= img
->Height2
; /* without border, power of two */
1422 const GLint depth
= img
->Depth2
; /* without border, power of two */
1426 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
1427 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
1428 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapR
, texcoord
[2], depth
, k
);
1430 if (i
< 0 || i
>= (GLint
) img
->Width
||
1431 j
< 0 || j
>= (GLint
) img
->Height
||
1432 k
< 0 || k
>= (GLint
) img
->Depth
) {
1433 /* Need this test for GL_CLAMP_TO_BORDER mode */
1434 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
1437 img
->FetchTexelc(img
, i
, j
, k
, rgba
);
1444 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1447 sample_3d_linear(GLcontext
*ctx
,
1448 const struct gl_texture_object
*tObj
,
1449 const struct gl_texture_image
*img
,
1450 const GLfloat texcoord
[4],
1453 const GLint width
= img
->Width2
;
1454 const GLint height
= img
->Height2
;
1455 const GLint depth
= img
->Depth2
;
1456 GLint i0
, j0
, k0
, i1
, j1
, k1
;
1457 GLbitfield useBorderColor
= 0x0;
1460 GLchan t000
[4], t010
[4], t001
[4], t011
[4];
1461 GLchan t100
[4], t110
[4], t101
[4], t111
[4];
1463 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
1464 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
1465 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapR
, texcoord
[2], w
, depth
, k0
, k1
);
1476 /* check if sampling texture border color */
1477 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1478 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1479 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1480 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1481 if (k0
< 0 || k0
>= depth
) useBorderColor
|= K0BIT
;
1482 if (k1
< 0 || k1
>= depth
) useBorderColor
|= K1BIT
;
1486 if (useBorderColor
& (I0BIT
| J0BIT
| K0BIT
)) {
1487 COPY_CHAN4(t000
, tObj
->_BorderChan
);
1490 img
->FetchTexelc(img
, i0
, j0
, k0
, t000
);
1492 if (useBorderColor
& (I1BIT
| J0BIT
| K0BIT
)) {
1493 COPY_CHAN4(t100
, tObj
->_BorderChan
);
1496 img
->FetchTexelc(img
, i1
, j0
, k0
, t100
);
1498 if (useBorderColor
& (I0BIT
| J1BIT
| K0BIT
)) {
1499 COPY_CHAN4(t010
, tObj
->_BorderChan
);
1502 img
->FetchTexelc(img
, i0
, j1
, k0
, t010
);
1504 if (useBorderColor
& (I1BIT
| J1BIT
| K0BIT
)) {
1505 COPY_CHAN4(t110
, tObj
->_BorderChan
);
1508 img
->FetchTexelc(img
, i1
, j1
, k0
, t110
);
1511 if (useBorderColor
& (I0BIT
| J0BIT
| K1BIT
)) {
1512 COPY_CHAN4(t001
, tObj
->_BorderChan
);
1515 img
->FetchTexelc(img
, i0
, j0
, k1
, t001
);
1517 if (useBorderColor
& (I1BIT
| J0BIT
| K1BIT
)) {
1518 COPY_CHAN4(t101
, tObj
->_BorderChan
);
1521 img
->FetchTexelc(img
, i1
, j0
, k1
, t101
);
1523 if (useBorderColor
& (I0BIT
| J1BIT
| K1BIT
)) {
1524 COPY_CHAN4(t011
, tObj
->_BorderChan
);
1527 img
->FetchTexelc(img
, i0
, j1
, k1
, t011
);
1529 if (useBorderColor
& (I1BIT
| J1BIT
| K1BIT
)) {
1530 COPY_CHAN4(t111
, tObj
->_BorderChan
);
1533 img
->FetchTexelc(img
, i1
, j1
, k1
, t111
);
1536 /* trilinear interpolation of samples */
1540 lerp_rgba_3d(rgba
, a
, b
, c
, t000
, t100
, t010
, t110
, t001
, t101
, t011
, t111
);
1546 sample_3d_nearest_mipmap_nearest(GLcontext
*ctx
,
1547 const struct gl_texture_object
*tObj
,
1548 GLuint n
, const GLfloat texcoord
[][4],
1549 const GLfloat lambda
[], GLchan rgba
[][4] )
1552 for (i
= 0; i
< n
; i
++) {
1553 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1554 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1560 sample_3d_linear_mipmap_nearest(GLcontext
*ctx
,
1561 const struct gl_texture_object
*tObj
,
1562 GLuint n
, const GLfloat texcoord
[][4],
1563 const GLfloat lambda
[], GLchan rgba
[][4])
1566 ASSERT(lambda
!= NULL
);
1567 for (i
= 0; i
< n
; i
++) {
1568 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1569 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1575 sample_3d_nearest_mipmap_linear(GLcontext
*ctx
,
1576 const struct gl_texture_object
*tObj
,
1577 GLuint n
, const GLfloat texcoord
[][4],
1578 const GLfloat lambda
[], GLchan rgba
[][4])
1581 ASSERT(lambda
!= NULL
);
1582 for (i
= 0; i
< n
; i
++) {
1583 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1584 if (level
>= tObj
->_MaxLevel
) {
1585 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1586 texcoord
[i
], rgba
[i
]);
1589 GLchan t0
[4], t1
[4]; /* texels */
1590 const GLfloat f
= FRAC(lambda
[i
]);
1591 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1592 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1593 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1600 sample_3d_linear_mipmap_linear(GLcontext
*ctx
,
1601 const struct gl_texture_object
*tObj
,
1602 GLuint n
, const GLfloat texcoord
[][4],
1603 const GLfloat lambda
[], GLchan rgba
[][4])
1606 ASSERT(lambda
!= NULL
);
1607 for (i
= 0; i
< n
; i
++) {
1608 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1609 if (level
>= tObj
->_MaxLevel
) {
1610 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1611 texcoord
[i
], rgba
[i
]);
1614 GLchan t0
[4], t1
[4]; /* texels */
1615 const GLfloat f
= FRAC(lambda
[i
]);
1616 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1617 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1618 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1625 sample_nearest_3d(GLcontext
*ctx
,
1626 const struct gl_texture_object
*tObj
, GLuint n
,
1627 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1631 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1634 sample_3d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1641 sample_linear_3d( GLcontext
*ctx
,
1642 const struct gl_texture_object
*tObj
, GLuint n
,
1643 const GLfloat texcoords
[][4],
1644 const GLfloat lambda
[], GLchan rgba
[][4] )
1647 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1650 sample_3d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1656 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
1657 * return a texture sample.
1660 sample_lambda_3d( GLcontext
*ctx
,
1661 const struct gl_texture_object
*tObj
, GLuint n
,
1662 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1665 GLuint minStart
, minEnd
; /* texels with minification */
1666 GLuint magStart
, magEnd
; /* texels with magnification */
1669 ASSERT(lambda
!= NULL
);
1670 compute_min_mag_ranges(tObj
, n
, lambda
,
1671 &minStart
, &minEnd
, &magStart
, &magEnd
);
1673 if (minStart
< minEnd
) {
1674 /* do the minified texels */
1675 GLuint m
= minEnd
- minStart
;
1676 switch (tObj
->MinFilter
) {
1678 for (i
= minStart
; i
< minEnd
; i
++)
1679 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1680 texcoords
[i
], rgba
[i
]);
1683 for (i
= minStart
; i
< minEnd
; i
++)
1684 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1685 texcoords
[i
], rgba
[i
]);
1687 case GL_NEAREST_MIPMAP_NEAREST
:
1688 sample_3d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1689 lambda
+ minStart
, rgba
+ minStart
);
1691 case GL_LINEAR_MIPMAP_NEAREST
:
1692 sample_3d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1693 lambda
+ minStart
, rgba
+ minStart
);
1695 case GL_NEAREST_MIPMAP_LINEAR
:
1696 sample_3d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1697 lambda
+ minStart
, rgba
+ minStart
);
1699 case GL_LINEAR_MIPMAP_LINEAR
:
1700 sample_3d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1701 lambda
+ minStart
, rgba
+ minStart
);
1704 _mesa_problem(ctx
, "Bad min filter in sample_3d_texture");
1709 if (magStart
< magEnd
) {
1710 /* do the magnified texels */
1711 switch (tObj
->MagFilter
) {
1713 for (i
= magStart
; i
< magEnd
; i
++)
1714 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1715 texcoords
[i
], rgba
[i
]);
1718 for (i
= magStart
; i
< magEnd
; i
++)
1719 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1720 texcoords
[i
], rgba
[i
]);
1723 _mesa_problem(ctx
, "Bad mag filter in sample_3d_texture");
1730 /**********************************************************************/
1731 /* Texture Cube Map Sampling Functions */
1732 /**********************************************************************/
1735 * Choose one of six sides of a texture cube map given the texture
1736 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1739 static const struct gl_texture_image
**
1740 choose_cube_face(const struct gl_texture_object
*texObj
,
1741 const GLfloat texcoord
[4], GLfloat newCoord
[4])
1745 direction target sc tc ma
1746 ---------- ------------------------------- --- --- ---
1747 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1748 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1749 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1750 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1751 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1752 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1754 const GLfloat rx
= texcoord
[0];
1755 const GLfloat ry
= texcoord
[1];
1756 const GLfloat rz
= texcoord
[2];
1757 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
1761 if (arx
> ary
&& arx
> arz
) {
1775 else if (ary
> arx
&& ary
> arz
) {
1804 newCoord
[0] = ( sc
/ ma
+ 1.0F
) * 0.5F
;
1805 newCoord
[1] = ( tc
/ ma
+ 1.0F
) * 0.5F
;
1806 return (const struct gl_texture_image
**) texObj
->Image
[face
];
1811 sample_nearest_cube(GLcontext
*ctx
,
1812 const struct gl_texture_object
*tObj
, GLuint n
,
1813 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1818 for (i
= 0; i
< n
; i
++) {
1819 const struct gl_texture_image
**images
;
1820 GLfloat newCoord
[4];
1821 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1822 sample_2d_nearest(ctx
, tObj
, images
[tObj
->BaseLevel
],
1829 sample_linear_cube(GLcontext
*ctx
,
1830 const struct gl_texture_object
*tObj
, GLuint n
,
1831 const GLfloat texcoords
[][4],
1832 const GLfloat lambda
[], GLchan rgba
[][4])
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_linear(ctx
, tObj
, images
[tObj
->BaseLevel
],
1847 sample_cube_nearest_mipmap_nearest(GLcontext
*ctx
,
1848 const struct gl_texture_object
*tObj
,
1849 GLuint n
, const GLfloat texcoord
[][4],
1850 const GLfloat lambda
[], GLchan rgba
[][4])
1853 ASSERT(lambda
!= NULL
);
1854 for (i
= 0; i
< n
; i
++) {
1855 const struct gl_texture_image
**images
;
1856 GLfloat newCoord
[4];
1858 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1860 /* XXX we actually need to recompute lambda here based on the newCoords.
1861 * But we would need the texcoords of adjacent fragments to compute that
1862 * properly, and we don't have those here.
1863 * For now, do an approximation: subtracting 1 from the chosen mipmap
1864 * level seems to work in some test cases.
1865 * The same adjustment is done in the next few functions.
1867 level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1868 level
= MAX2(level
- 1, 0);
1870 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1876 sample_cube_linear_mipmap_nearest(GLcontext
*ctx
,
1877 const struct gl_texture_object
*tObj
,
1878 GLuint n
, const GLfloat texcoord
[][4],
1879 const GLfloat lambda
[], GLchan rgba
[][4])
1882 ASSERT(lambda
!= NULL
);
1883 for (i
= 0; i
< n
; i
++) {
1884 const struct gl_texture_image
**images
;
1885 GLfloat newCoord
[4];
1886 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1887 level
= MAX2(level
- 1, 0); /* see comment above */
1888 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1889 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1895 sample_cube_nearest_mipmap_linear(GLcontext
*ctx
,
1896 const struct gl_texture_object
*tObj
,
1897 GLuint n
, const GLfloat texcoord
[][4],
1898 const GLfloat lambda
[], GLchan rgba
[][4])
1901 ASSERT(lambda
!= NULL
);
1902 for (i
= 0; i
< n
; i
++) {
1903 const struct gl_texture_image
**images
;
1904 GLfloat newCoord
[4];
1905 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1906 level
= MAX2(level
- 1, 0); /* see comment above */
1907 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1908 if (level
>= tObj
->_MaxLevel
) {
1909 sample_2d_nearest(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1913 GLchan t0
[4], t1
[4]; /* texels */
1914 const GLfloat f
= FRAC(lambda
[i
]);
1915 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, t0
);
1916 sample_2d_nearest(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1917 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1924 sample_cube_linear_mipmap_linear(GLcontext
*ctx
,
1925 const struct gl_texture_object
*tObj
,
1926 GLuint n
, const GLfloat texcoord
[][4],
1927 const GLfloat lambda
[], GLchan rgba
[][4])
1930 ASSERT(lambda
!= NULL
);
1931 for (i
= 0; i
< n
; i
++) {
1932 const struct gl_texture_image
**images
;
1933 GLfloat newCoord
[4];
1934 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1935 level
= MAX2(level
- 1, 0); /* see comment above */
1936 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1937 if (level
>= tObj
->_MaxLevel
) {
1938 sample_2d_linear(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1942 GLchan t0
[4], t1
[4];
1943 const GLfloat f
= FRAC(lambda
[i
]);
1944 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, t0
);
1945 sample_2d_linear(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1946 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1953 sample_lambda_cube( GLcontext
*ctx
,
1954 const struct gl_texture_object
*tObj
, GLuint n
,
1955 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1958 GLuint minStart
, minEnd
; /* texels with minification */
1959 GLuint magStart
, magEnd
; /* texels with magnification */
1961 ASSERT(lambda
!= NULL
);
1962 compute_min_mag_ranges(tObj
, n
, lambda
,
1963 &minStart
, &minEnd
, &magStart
, &magEnd
);
1965 if (minStart
< minEnd
) {
1966 /* do the minified texels */
1967 const GLuint m
= minEnd
- minStart
;
1968 switch (tObj
->MinFilter
) {
1970 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1971 lambda
+ minStart
, rgba
+ minStart
);
1974 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1975 lambda
+ minStart
, rgba
+ minStart
);
1977 case GL_NEAREST_MIPMAP_NEAREST
:
1978 sample_cube_nearest_mipmap_nearest(ctx
, tObj
, m
,
1979 texcoords
+ minStart
,
1980 lambda
+ minStart
, rgba
+ minStart
);
1982 case GL_LINEAR_MIPMAP_NEAREST
:
1983 sample_cube_linear_mipmap_nearest(ctx
, tObj
, m
,
1984 texcoords
+ minStart
,
1985 lambda
+ minStart
, rgba
+ minStart
);
1987 case GL_NEAREST_MIPMAP_LINEAR
:
1988 sample_cube_nearest_mipmap_linear(ctx
, tObj
, m
,
1989 texcoords
+ minStart
,
1990 lambda
+ minStart
, rgba
+ minStart
);
1992 case GL_LINEAR_MIPMAP_LINEAR
:
1993 sample_cube_linear_mipmap_linear(ctx
, tObj
, m
,
1994 texcoords
+ minStart
,
1995 lambda
+ minStart
, rgba
+ minStart
);
1998 _mesa_problem(ctx
, "Bad min filter in sample_lambda_cube");
2002 if (magStart
< magEnd
) {
2003 /* do the magnified texels */
2004 const GLuint m
= magEnd
- magStart
;
2005 switch (tObj
->MagFilter
) {
2007 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2008 lambda
+ magStart
, rgba
+ magStart
);
2011 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2012 lambda
+ magStart
, rgba
+ magStart
);
2015 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_cube");
2021 /**********************************************************************/
2022 /* Texture Rectangle Sampling Functions */
2023 /**********************************************************************/
2027 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
2030 clamp_rect_coord_nearest(GLenum wrapMode
, GLfloat coord
, GLint max
)
2032 if (wrapMode
== GL_CLAMP
) {
2033 return IFLOOR( CLAMP(coord
, 0.0F
, max
- 1) );
2035 else if (wrapMode
== GL_CLAMP_TO_EDGE
) {
2036 return IFLOOR( CLAMP(coord
, 0.5F
, max
- 0.5F
) );
2039 return IFLOOR( CLAMP(coord
, -0.5F
, max
+ 0.5F
) );
2045 * As above, but GL_LINEAR filtering.
2048 clamp_rect_coord_linear(GLenum wrapMode
, GLfloat coord
, GLint max
,
2049 GLint
*i0out
, GLint
*i1out
)
2053 if (wrapMode
== GL_CLAMP
) {
2054 /* Not exactly what the spec says, but it matches NVIDIA output */
2055 fcol
= CLAMP(coord
- 0.5F
, 0.0, max
-1);
2059 else if (wrapMode
== GL_CLAMP_TO_EDGE
) {
2060 fcol
= CLAMP(coord
, 0.5F
, max
- 0.5F
);
2068 ASSERT(wrapMode
== GL_CLAMP_TO_BORDER
);
2069 fcol
= CLAMP(coord
, -0.5F
, max
+ 0.5F
);
2080 sample_nearest_rect(GLcontext
*ctx
,
2081 const struct gl_texture_object
*tObj
, GLuint n
,
2082 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2085 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2086 const GLfloat width
= (GLfloat
) img
->Width
;
2087 const GLfloat height
= (GLfloat
) img
->Height
;
2088 const GLint width_minus_1
= img
->Width
- 1;
2089 const GLint height_minus_1
= img
->Height
- 1;
2095 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2096 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2097 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2098 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2099 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2100 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2101 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2103 for (i
= 0; i
< n
; i
++) {
2105 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2106 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2107 if (col
< 0 || col
> width_minus_1
|| row
< 0 || row
> height_minus_1
)
2108 COPY_CHAN4(rgba
[i
], tObj
->_BorderChan
);
2110 img
->FetchTexelc(img
, col
, row
, 0, rgba
[i
]);
2116 sample_linear_rect(GLcontext
*ctx
,
2117 const struct gl_texture_object
*tObj
, GLuint n
,
2118 const GLfloat texcoords
[][4],
2119 const GLfloat lambda
[], GLchan rgba
[][4])
2121 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2122 const GLfloat width
= (GLfloat
) img
->Width
;
2123 const GLfloat height
= (GLfloat
) img
->Height
;
2124 const GLint width_minus_1
= img
->Width
- 1;
2125 const GLint height_minus_1
= img
->Height
- 1;
2131 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2132 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2133 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2134 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2135 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2136 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2137 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2139 /* XXX lots of opportunity for optimization in this loop */
2140 for (i
= 0; i
< n
; i
++) {
2142 GLint i0
, j0
, i1
, j1
;
2143 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2145 GLbitfield useBorderColor
= 0x0;
2147 /* NOTE: we DO NOT use [0, 1] texture coordinates! */
2148 if (tObj
->WrapS
== GL_CLAMP
) {
2149 /* Not exactly what the spec says, but it matches NVIDIA output */
2150 fcol
= CLAMP(texcoords
[i
][0] - 0.5F
, 0.0, width_minus_1
);
2154 else if (tObj
->WrapS
== GL_CLAMP_TO_EDGE
) {
2155 fcol
= CLAMP(texcoords
[i
][0], 0.5F
, width
- 0.5F
);
2159 if (i1
> width_minus_1
)
2163 ASSERT(tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2164 fcol
= CLAMP(texcoords
[i
][0], -0.5F
, width
+ 0.5F
);
2170 if (tObj
->WrapT
== GL_CLAMP
) {
2171 /* Not exactly what the spec says, but it matches NVIDIA output */
2172 frow
= CLAMP(texcoords
[i
][1] - 0.5F
, 0.0, width_minus_1
);
2176 else if (tObj
->WrapT
== GL_CLAMP_TO_EDGE
) {
2177 frow
= CLAMP(texcoords
[i
][1], 0.5F
, height
- 0.5F
);
2181 if (j1
> height_minus_1
)
2182 j1
= height_minus_1
;
2185 ASSERT(tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2186 frow
= CLAMP(texcoords
[i
][1], -0.5F
, height
+ 0.5F
);
2192 /* compute integer rows/columns */
2193 if (i0
< 0 || i0
> width_minus_1
) useBorderColor
|= I0BIT
;
2194 if (i1
< 0 || i1
> width_minus_1
) useBorderColor
|= I1BIT
;
2195 if (j0
< 0 || j0
> height_minus_1
) useBorderColor
|= J0BIT
;
2196 if (j1
< 0 || j1
> height_minus_1
) useBorderColor
|= J1BIT
;
2198 /* get four texel samples */
2199 if (useBorderColor
& (I0BIT
| J0BIT
))
2200 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2202 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
2204 if (useBorderColor
& (I1BIT
| J0BIT
))
2205 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2207 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
2209 if (useBorderColor
& (I0BIT
| J1BIT
))
2210 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2212 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
2214 if (useBorderColor
& (I1BIT
| J1BIT
))
2215 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2217 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
2219 /* compute interpolants */
2223 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2229 sample_lambda_rect( GLcontext
*ctx
,
2230 const struct gl_texture_object
*tObj
, GLuint n
,
2231 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2234 GLuint minStart
, minEnd
, magStart
, magEnd
;
2236 /* We only need lambda to decide between minification and magnification.
2237 * There is no mipmapping with rectangular textures.
2239 compute_min_mag_ranges(tObj
, n
, lambda
,
2240 &minStart
, &minEnd
, &magStart
, &magEnd
);
2242 if (minStart
< minEnd
) {
2243 if (tObj
->MinFilter
== GL_NEAREST
) {
2244 sample_nearest_rect( ctx
, tObj
, minEnd
- minStart
,
2245 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2248 sample_linear_rect( ctx
, tObj
, minEnd
- minStart
,
2249 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2252 if (magStart
< magEnd
) {
2253 if (tObj
->MagFilter
== GL_NEAREST
) {
2254 sample_nearest_rect( ctx
, tObj
, magEnd
- magStart
,
2255 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2258 sample_linear_rect( ctx
, tObj
, magEnd
- magStart
,
2259 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2266 /**********************************************************************/
2267 /* 2D Texture Array Sampling Functions */
2268 /**********************************************************************/
2271 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2274 sample_2d_array_nearest(GLcontext
*ctx
,
2275 const struct gl_texture_object
*tObj
,
2276 const struct gl_texture_image
*img
,
2277 const GLfloat texcoord
[4],
2280 const GLint width
= img
->Width2
; /* without border, power of two */
2281 const GLint height
= img
->Height2
; /* without border, power of two */
2282 const GLint depth
= img
->Depth
;
2287 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
2288 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoord
[1], height
, j
);
2289 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2291 if (i
< 0 || i
>= (GLint
) img
->Width
||
2292 j
< 0 || j
>= (GLint
) img
->Height
||
2293 array
< 0 || array
>= (GLint
) img
->Depth
) {
2294 /* Need this test for GL_CLAMP_TO_BORDER mode */
2295 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2298 img
->FetchTexelc(img
, i
, j
, array
, rgba
);
2305 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2308 sample_2d_array_linear(GLcontext
*ctx
,
2309 const struct gl_texture_object
*tObj
,
2310 const struct gl_texture_image
*img
,
2311 const GLfloat texcoord
[4],
2314 const GLint width
= img
->Width2
;
2315 const GLint height
= img
->Height2
;
2316 const GLint depth
= img
->Depth
;
2317 GLint i0
, j0
, i1
, j1
;
2319 GLbitfield useBorderColor
= 0x0;
2322 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2324 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
2325 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoord
[1], v
, height
, j0
, j1
);
2326 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2328 if (array
< 0 || array
>= depth
) {
2329 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2339 /* check if sampling texture border color */
2340 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2341 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2342 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2343 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2347 if (useBorderColor
& (I0BIT
| J0BIT
)) {
2348 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2351 img
->FetchTexelc(img
, i0
, j0
, array
, t00
);
2353 if (useBorderColor
& (I1BIT
| J0BIT
)) {
2354 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2357 img
->FetchTexelc(img
, i1
, j0
, array
, t10
);
2359 if (useBorderColor
& (I0BIT
| J1BIT
)) {
2360 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2363 img
->FetchTexelc(img
, i0
, j1
, array
, t01
);
2365 if (useBorderColor
& (I1BIT
| J1BIT
)) {
2366 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2369 img
->FetchTexelc(img
, i1
, j1
, array
, t11
);
2372 /* trilinear interpolation of samples */
2375 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
2382 sample_2d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2383 const struct gl_texture_object
*tObj
,
2384 GLuint n
, const GLfloat texcoord
[][4],
2385 const GLfloat lambda
[], GLchan rgba
[][4] )
2388 for (i
= 0; i
< n
; i
++) {
2389 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2390 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2397 sample_2d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2398 const struct gl_texture_object
*tObj
,
2399 GLuint n
, const GLfloat texcoord
[][4],
2400 const GLfloat lambda
[], GLchan rgba
[][4])
2403 ASSERT(lambda
!= NULL
);
2404 for (i
= 0; i
< n
; i
++) {
2405 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2406 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2407 texcoord
[i
], rgba
[i
]);
2413 sample_2d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2414 const struct gl_texture_object
*tObj
,
2415 GLuint n
, const GLfloat texcoord
[][4],
2416 const GLfloat lambda
[], GLchan rgba
[][4])
2419 ASSERT(lambda
!= NULL
);
2420 for (i
= 0; i
< n
; i
++) {
2421 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2422 if (level
>= tObj
->_MaxLevel
) {
2423 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2424 texcoord
[i
], rgba
[i
]);
2427 GLchan t0
[4], t1
[4]; /* texels */
2428 const GLfloat f
= FRAC(lambda
[i
]);
2429 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2430 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2431 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2438 sample_2d_array_linear_mipmap_linear(GLcontext
*ctx
,
2439 const struct gl_texture_object
*tObj
,
2440 GLuint n
, const GLfloat texcoord
[][4],
2441 const GLfloat lambda
[], GLchan rgba
[][4])
2444 ASSERT(lambda
!= NULL
);
2445 for (i
= 0; i
< n
; i
++) {
2446 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2447 if (level
>= tObj
->_MaxLevel
) {
2448 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2449 texcoord
[i
], rgba
[i
]);
2452 GLchan t0
[4], t1
[4]; /* texels */
2453 const GLfloat f
= FRAC(lambda
[i
]);
2454 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2455 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2456 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2463 sample_nearest_2d_array(GLcontext
*ctx
,
2464 const struct gl_texture_object
*tObj
, GLuint n
,
2465 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2469 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2472 sample_2d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2479 sample_linear_2d_array(GLcontext
*ctx
,
2480 const struct gl_texture_object
*tObj
, GLuint n
,
2481 const GLfloat texcoords
[][4],
2482 const GLfloat lambda
[], GLchan rgba
[][4])
2485 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2488 sample_2d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2494 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
2495 * return a texture sample.
2498 sample_lambda_2d_array(GLcontext
*ctx
,
2499 const struct gl_texture_object
*tObj
, GLuint n
,
2500 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2503 GLuint minStart
, minEnd
; /* texels with minification */
2504 GLuint magStart
, magEnd
; /* texels with magnification */
2507 ASSERT(lambda
!= NULL
);
2508 compute_min_mag_ranges(tObj
, n
, lambda
,
2509 &minStart
, &minEnd
, &magStart
, &magEnd
);
2511 if (minStart
< minEnd
) {
2512 /* do the minified texels */
2513 GLuint m
= minEnd
- minStart
;
2514 switch (tObj
->MinFilter
) {
2516 for (i
= minStart
; i
< minEnd
; i
++)
2517 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2518 texcoords
[i
], rgba
[i
]);
2521 for (i
= minStart
; i
< minEnd
; i
++)
2522 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2523 texcoords
[i
], rgba
[i
]);
2525 case GL_NEAREST_MIPMAP_NEAREST
:
2526 sample_2d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2527 lambda
+ minStart
, rgba
+ minStart
);
2529 case GL_LINEAR_MIPMAP_NEAREST
:
2530 sample_2d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2531 texcoords
+ minStart
,
2535 case GL_NEAREST_MIPMAP_LINEAR
:
2536 sample_2d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2537 lambda
+ minStart
, rgba
+ minStart
);
2539 case GL_LINEAR_MIPMAP_LINEAR
:
2540 sample_2d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2541 texcoords
+ minStart
,
2546 _mesa_problem(ctx
, "Bad min filter in sample_2d_array_texture");
2551 if (magStart
< magEnd
) {
2552 /* do the magnified texels */
2553 switch (tObj
->MagFilter
) {
2555 for (i
= magStart
; i
< magEnd
; i
++)
2556 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2557 texcoords
[i
], rgba
[i
]);
2560 for (i
= magStart
; i
< magEnd
; i
++)
2561 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2562 texcoords
[i
], rgba
[i
]);
2565 _mesa_problem(ctx
, "Bad mag filter in sample_2d_array_texture");
2574 /**********************************************************************/
2575 /* 1D Texture Array Sampling Functions */
2576 /**********************************************************************/
2579 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2582 sample_1d_array_nearest(GLcontext
*ctx
,
2583 const struct gl_texture_object
*tObj
,
2584 const struct gl_texture_image
*img
,
2585 const GLfloat texcoord
[4],
2588 const GLint width
= img
->Width2
; /* without border, power of two */
2589 const GLint height
= img
->Height
;
2594 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoord
[0], width
, i
);
2595 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2597 if (i
< 0 || i
>= (GLint
) img
->Width
||
2598 array
< 0 || array
>= (GLint
) img
->Height
) {
2599 /* Need this test for GL_CLAMP_TO_BORDER mode */
2600 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2603 img
->FetchTexelc(img
, i
, array
, 0, rgba
);
2610 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2613 sample_1d_array_linear(GLcontext
*ctx
,
2614 const struct gl_texture_object
*tObj
,
2615 const struct gl_texture_image
*img
,
2616 const GLfloat texcoord
[4],
2619 const GLint width
= img
->Width2
;
2620 const GLint height
= img
->Height
;
2623 GLbitfield useBorderColor
= 0x0;
2626 GLchan t0
[4], t1
[4];
2628 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoord
[0], u
, width
, i0
, i1
);
2629 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2636 /* check if sampling texture border color */
2637 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2638 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2641 if (array
< 0 || array
>= height
) useBorderColor
|= K0BIT
;
2644 if (useBorderColor
& (I0BIT
| K0BIT
)) {
2645 COPY_CHAN4(t0
, tObj
->_BorderChan
);
2648 img
->FetchTexelc(img
, i0
, array
, 0, t0
);
2650 if (useBorderColor
& (I1BIT
| K0BIT
)) {
2651 COPY_CHAN4(t1
, tObj
->_BorderChan
);
2654 img
->FetchTexelc(img
, i1
, array
, 0, t1
);
2657 /* bilinear interpolation of samples */
2659 lerp_rgba(rgba
, a
, t0
, t1
);
2665 sample_1d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2666 const struct gl_texture_object
*tObj
,
2667 GLuint n
, const GLfloat texcoord
[][4],
2668 const GLfloat lambda
[], GLchan rgba
[][4] )
2671 for (i
= 0; i
< n
; i
++) {
2672 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2673 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2680 sample_1d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2681 const struct gl_texture_object
*tObj
,
2682 GLuint n
, const GLfloat texcoord
[][4],
2683 const GLfloat lambda
[], GLchan rgba
[][4])
2686 ASSERT(lambda
!= NULL
);
2687 for (i
= 0; i
< n
; i
++) {
2688 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2689 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2690 texcoord
[i
], rgba
[i
]);
2696 sample_1d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2697 const struct gl_texture_object
*tObj
,
2698 GLuint n
, const GLfloat texcoord
[][4],
2699 const GLfloat lambda
[], GLchan rgba
[][4])
2702 ASSERT(lambda
!= NULL
);
2703 for (i
= 0; i
< n
; i
++) {
2704 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2705 if (level
>= tObj
->_MaxLevel
) {
2706 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2707 texcoord
[i
], rgba
[i
]);
2710 GLchan t0
[4], t1
[4]; /* texels */
2711 const GLfloat f
= FRAC(lambda
[i
]);
2712 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2713 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2714 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2721 sample_1d_array_linear_mipmap_linear(GLcontext
*ctx
,
2722 const struct gl_texture_object
*tObj
,
2723 GLuint n
, const GLfloat texcoord
[][4],
2724 const GLfloat lambda
[], GLchan rgba
[][4])
2727 ASSERT(lambda
!= NULL
);
2728 for (i
= 0; i
< n
; i
++) {
2729 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2730 if (level
>= tObj
->_MaxLevel
) {
2731 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2732 texcoord
[i
], rgba
[i
]);
2735 GLchan t0
[4], t1
[4]; /* texels */
2736 const GLfloat f
= FRAC(lambda
[i
]);
2737 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2738 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2739 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2746 sample_nearest_1d_array(GLcontext
*ctx
,
2747 const struct gl_texture_object
*tObj
, GLuint n
,
2748 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2752 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2755 sample_1d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2762 sample_linear_1d_array(GLcontext
*ctx
,
2763 const struct gl_texture_object
*tObj
, GLuint n
,
2764 const GLfloat texcoords
[][4],
2765 const GLfloat lambda
[], GLchan rgba
[][4])
2768 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2771 sample_1d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2777 * Given an (s,t,r) texture coordinate and lambda (level of detail) value,
2778 * return a texture sample.
2781 sample_lambda_1d_array(GLcontext
*ctx
,
2782 const struct gl_texture_object
*tObj
, GLuint n
,
2783 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2786 GLuint minStart
, minEnd
; /* texels with minification */
2787 GLuint magStart
, magEnd
; /* texels with magnification */
2790 ASSERT(lambda
!= NULL
);
2791 compute_min_mag_ranges(tObj
, n
, lambda
,
2792 &minStart
, &minEnd
, &magStart
, &magEnd
);
2794 if (minStart
< minEnd
) {
2795 /* do the minified texels */
2796 GLuint m
= minEnd
- minStart
;
2797 switch (tObj
->MinFilter
) {
2799 for (i
= minStart
; i
< minEnd
; i
++)
2800 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2801 texcoords
[i
], rgba
[i
]);
2804 for (i
= minStart
; i
< minEnd
; i
++)
2805 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2806 texcoords
[i
], rgba
[i
]);
2808 case GL_NEAREST_MIPMAP_NEAREST
:
2809 sample_1d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2810 lambda
+ minStart
, rgba
+ minStart
);
2812 case GL_LINEAR_MIPMAP_NEAREST
:
2813 sample_1d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2814 texcoords
+ minStart
,
2818 case GL_NEAREST_MIPMAP_LINEAR
:
2819 sample_1d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2820 lambda
+ minStart
, rgba
+ minStart
);
2822 case GL_LINEAR_MIPMAP_LINEAR
:
2823 sample_1d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2824 texcoords
+ minStart
,
2829 _mesa_problem(ctx
, "Bad min filter in sample_1d_array_texture");
2834 if (magStart
< magEnd
) {
2835 /* do the magnified texels */
2836 switch (tObj
->MagFilter
) {
2838 for (i
= magStart
; i
< magEnd
; i
++)
2839 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2840 texcoords
[i
], rgba
[i
]);
2843 for (i
= magStart
; i
< magEnd
; i
++)
2844 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2845 texcoords
[i
], rgba
[i
]);
2848 _mesa_problem(ctx
, "Bad mag filter in sample_1d_array_texture");
2858 * Sample a shadow/depth texture.
2861 sample_depth_texture( GLcontext
*ctx
,
2862 const struct gl_texture_object
*tObj
, GLuint n
,
2863 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2866 const GLint baseLevel
= tObj
->BaseLevel
;
2867 const struct gl_texture_image
*img
= tObj
->Image
[0][baseLevel
];
2868 const GLint width
= img
->Width
;
2869 const GLint height
= img
->Height
;
2870 const GLint depth
= img
->Depth
;
2871 const GLuint compare_coord
= (tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
)
2879 ASSERT(img
->TexFormat
->BaseFormat
== GL_DEPTH_COMPONENT
||
2880 img
->TexFormat
->BaseFormat
== GL_DEPTH_STENCIL_EXT
);
2882 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
2883 tObj
->Target
== GL_TEXTURE_2D
||
2884 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
||
2885 tObj
->Target
== GL_TEXTURE_1D_ARRAY_EXT
||
2886 tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
);
2888 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2890 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2892 function
= tObj
->_Function
;
2893 if (tObj
->MagFilter
== GL_NEAREST
) {
2895 for (i
= 0; i
< n
; i
++) {
2896 GLfloat depthSample
;
2897 GLint col
, row
, slice
;
2899 switch (tObj
->Target
) {
2900 case GL_TEXTURE_RECTANGLE_ARB
:
2901 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2902 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2907 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2914 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2916 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoords
[i
][1],
2921 case GL_TEXTURE_1D_ARRAY_EXT
:
2922 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2924 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2927 case GL_TEXTURE_2D_ARRAY_EXT
:
2928 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapS
, texcoords
[i
][0],
2930 COMPUTE_NEAREST_TEXEL_LOCATION(tObj
->WrapT
, texcoords
[i
][1],
2932 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2936 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
&&
2937 slice
>= 0 && slice
< depth
) {
2938 img
->FetchTexelf(img
, col
, row
, slice
, &depthSample
);
2941 depthSample
= tObj
->BorderColor
[0];
2946 result
= (texcoords
[i
][compare_coord
] <= depthSample
) ? CHAN_MAX
: ambient
;
2949 result
= (texcoords
[i
][compare_coord
] >= depthSample
) ? CHAN_MAX
: ambient
;
2952 result
= (texcoords
[i
][compare_coord
] < depthSample
) ? CHAN_MAX
: ambient
;
2955 result
= (texcoords
[i
][compare_coord
] > depthSample
) ? CHAN_MAX
: ambient
;
2958 result
= (texcoords
[i
][compare_coord
] == depthSample
) ? CHAN_MAX
: ambient
;
2961 result
= (texcoords
[i
][compare_coord
] != depthSample
) ? CHAN_MAX
: ambient
;
2970 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2973 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2977 switch (tObj
->DepthMode
) {
2979 texel
[i
][RCOMP
] = result
;
2980 texel
[i
][GCOMP
] = result
;
2981 texel
[i
][BCOMP
] = result
;
2982 texel
[i
][ACOMP
] = CHAN_MAX
;
2985 texel
[i
][RCOMP
] = result
;
2986 texel
[i
][GCOMP
] = result
;
2987 texel
[i
][BCOMP
] = result
;
2988 texel
[i
][ACOMP
] = result
;
2991 texel
[i
][RCOMP
] = 0;
2992 texel
[i
][GCOMP
] = 0;
2993 texel
[i
][BCOMP
] = 0;
2994 texel
[i
][ACOMP
] = result
;
2997 _mesa_problem(ctx
, "Bad depth texture mode");
3003 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
3004 for (i
= 0; i
< n
; i
++) {
3005 GLfloat depth00
, depth01
, depth10
, depth11
;
3006 GLint i0
, i1
, j0
, j1
;
3009 GLuint useBorderTexel
;
3011 switch (tObj
->Target
) {
3012 case GL_TEXTURE_RECTANGLE_ARB
:
3013 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0],
3015 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1],
3022 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3024 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoords
[i
][1],
3029 case GL_TEXTURE_1D_ARRAY_EXT
:
3030 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3032 j0
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
3036 case GL_TEXTURE_2D_ARRAY_EXT
:
3037 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapS
, texcoords
[i
][0],
3039 COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj
->WrapT
, texcoords
[i
][1],
3041 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
3049 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3055 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
3056 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
3057 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
3058 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
3061 if (slice
< 0 || slice
>= (GLint
) depth
) {
3062 depth00
= tObj
->BorderColor
[0];
3063 depth01
= tObj
->BorderColor
[0];
3064 depth10
= tObj
->BorderColor
[0];
3065 depth11
= tObj
->BorderColor
[0];
3068 /* get four depth samples from the texture */
3069 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
3070 depth00
= tObj
->BorderColor
[0];
3073 img
->FetchTexelf(img
, i0
, j0
, slice
, &depth00
);
3075 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
3076 depth10
= tObj
->BorderColor
[0];
3079 img
->FetchTexelf(img
, i1
, j0
, slice
, &depth10
);
3082 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3083 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
3084 depth01
= tObj
->BorderColor
[0];
3087 img
->FetchTexelf(img
, i0
, j1
, slice
, &depth01
);
3089 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
3090 depth11
= tObj
->BorderColor
[0];
3093 img
->FetchTexelf(img
, i1
, j1
, slice
, &depth11
);
3103 /* compute a single weighted depth sample and do one comparison */
3104 const GLfloat a
= FRAC(u
+ 1.0F
);
3105 const GLfloat b
= FRAC(v
+ 1.0F
);
3106 const GLfloat depthSample
3107 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3108 if ((depthSample
<= texcoords
[i
][compare_coord
] && function
== GL_LEQUAL
) ||
3109 (depthSample
>= texcoords
[i
][compare_coord
] && function
== GL_GEQUAL
)) {
3117 /* Do four depth/R comparisons and compute a weighted result.
3118 * If this touches on somebody's I.P., I'll remove this code
3121 const GLfloat d
= (CHAN_MAXF
- (GLfloat
) ambient
) * 0.25F
;
3122 GLfloat luminance
= CHAN_MAXF
;
3126 if (depth00
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3127 if (depth01
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3128 if (depth10
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3129 if (depth11
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3130 result
= (GLchan
) luminance
;
3133 if (depth00
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3134 if (depth01
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3135 if (depth10
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3136 if (depth11
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3137 result
= (GLchan
) luminance
;
3140 if (depth00
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3141 if (depth01
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3142 if (depth10
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3143 if (depth11
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3144 result
= (GLchan
) luminance
;
3147 if (depth00
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3148 if (depth01
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3149 if (depth10
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3150 if (depth11
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3151 result
= (GLchan
) luminance
;
3154 if (depth00
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3155 if (depth01
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3156 if (depth10
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3157 if (depth11
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3158 result
= (GLchan
) luminance
;
3161 if (depth00
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3162 if (depth01
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3163 if (depth10
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3164 if (depth11
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3165 result
= (GLchan
) luminance
;
3174 /* ordinary bilinear filtering */
3176 const GLfloat a
= FRAC(u
+ 1.0F
);
3177 const GLfloat b
= FRAC(v
+ 1.0F
);
3178 const GLfloat depthSample
3179 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3180 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
3184 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
3189 switch (tObj
->DepthMode
) {
3191 texel
[i
][RCOMP
] = result
;
3192 texel
[i
][GCOMP
] = result
;
3193 texel
[i
][BCOMP
] = result
;
3194 texel
[i
][ACOMP
] = CHAN_MAX
;
3197 texel
[i
][RCOMP
] = result
;
3198 texel
[i
][GCOMP
] = result
;
3199 texel
[i
][BCOMP
] = result
;
3200 texel
[i
][ACOMP
] = result
;
3203 texel
[i
][RCOMP
] = 0;
3204 texel
[i
][GCOMP
] = 0;
3205 texel
[i
][BCOMP
] = 0;
3206 texel
[i
][ACOMP
] = result
;
3209 _mesa_problem(ctx
, "Bad depth texture mode");
3218 * Experimental depth texture sampling function.
3221 sample_depth_texture2(const GLcontext
*ctx
,
3222 const struct gl_texture_unit
*texUnit
,
3223 GLuint n
, const GLfloat texcoords
[][4],
3226 const struct gl_texture_object
*texObj
= texUnit
->_Current
;
3227 const GLint baseLevel
= texObj
->BaseLevel
;
3228 const struct gl_texture_image
*texImage
= texObj
->Image
[0][baseLevel
];
3229 const GLuint width
= texImage
->Width
;
3230 const GLuint height
= texImage
->Height
;
3232 GLboolean lequal
, gequal
;
3234 if (texObj
->Target
!= GL_TEXTURE_2D
) {
3235 _mesa_problem(ctx
, "only 2-D depth textures supported at this time");
3239 if (texObj
->MinFilter
!= texObj
->MagFilter
) {
3240 _mesa_problem(ctx
, "mipmapped depth textures not supported at this time");
3244 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
3245 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
3246 * isn't a depth texture.
3248 if (texImage
->TexFormat
->BaseFormat
!= GL_DEPTH_COMPONENT
) {
3249 _mesa_problem(ctx
,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
3253 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
3255 if (texObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
3266 for (i
= 0; i
< n
; i
++) {
3268 GLint col
, row
, ii
, jj
, imin
, imax
, jmin
, jmax
, samples
, count
;
3271 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapS
, texcoords
[i
][0],
3273 COMPUTE_NEAREST_TEXEL_LOCATION(texObj
->WrapT
, texcoords
[i
][1],
3281 if (imin
< 0) imin
= 0;
3282 if (imax
>= width
) imax
= width
- 1;
3283 if (jmin
< 0) jmin
= 0;
3284 if (jmax
>= height
) jmax
= height
- 1;
3286 samples
= (imax
- imin
+ 1) * (jmax
- jmin
+ 1);
3288 for (jj
= jmin
; jj
<= jmax
; jj
++) {
3289 for (ii
= imin
; ii
<= imax
; ii
++) {
3290 GLfloat depthSample
;
3291 texImage
->FetchTexelf(texImage
, ii
, jj
, 0, &depthSample
);
3292 if ((depthSample
<= r
[i
] && lequal
) ||
3293 (depthSample
>= r
[i
] && gequal
)) {
3299 w
= (GLfloat
) count
/ (GLfloat
) samples
;
3300 w
= CHAN_MAXF
- w
* (CHAN_MAXF
- (GLfloat
) ambient
);
3303 texel
[i
][RCOMP
] = lum
;
3304 texel
[i
][GCOMP
] = lum
;
3305 texel
[i
][BCOMP
] = lum
;
3306 texel
[i
][ACOMP
] = CHAN_MAX
;
3314 * We use this function when a texture object is in an "incomplete" state.
3315 * When a fragment program attempts to sample an incomplete texture we
3316 * return black (see issue 23 in GL_ARB_fragment_program spec).
3317 * Note: fragment programs don't observe the texture enable/disable flags.
3320 null_sample_func( GLcontext
*ctx
,
3321 const struct gl_texture_object
*tObj
, GLuint n
,
3322 const GLfloat texcoords
[][4], const GLfloat lambda
[],
3330 for (i
= 0; i
< n
; i
++) {
3334 rgba
[i
][ACOMP
] = CHAN_MAX
;
3340 * Choose the texture sampling function for the given texture object.
3343 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
3344 const struct gl_texture_object
*t
)
3346 if (!t
|| !t
->_Complete
) {
3347 return &null_sample_func
;
3350 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
3351 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->TexFormat
->BaseFormat
;
3353 switch (t
->Target
) {
3355 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3356 return &sample_depth_texture
;
3358 else if (needLambda
) {
3359 return &sample_lambda_1d
;
3361 else if (t
->MinFilter
== GL_LINEAR
) {
3362 return &sample_linear_1d
;
3365 ASSERT(t
->MinFilter
== GL_NEAREST
);
3366 return &sample_nearest_1d
;
3369 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3370 return &sample_depth_texture
;
3372 else if (needLambda
) {
3373 return &sample_lambda_2d
;
3375 else if (t
->MinFilter
== GL_LINEAR
) {
3376 return &sample_linear_2d
;
3379 /* check for a few optimized cases */
3380 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
3381 ASSERT(t
->MinFilter
== GL_NEAREST
);
3382 if (t
->WrapS
== GL_REPEAT
&&
3383 t
->WrapT
== GL_REPEAT
&&
3384 img
->_IsPowerOfTwo
&&
3386 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGB
) {
3387 return &opt_sample_rgb_2d
;
3389 else if (t
->WrapS
== GL_REPEAT
&&
3390 t
->WrapT
== GL_REPEAT
&&
3391 img
->_IsPowerOfTwo
&&
3393 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGBA
) {
3394 return &opt_sample_rgba_2d
;
3397 return &sample_nearest_2d
;
3402 return &sample_lambda_3d
;
3404 else if (t
->MinFilter
== GL_LINEAR
) {
3405 return &sample_linear_3d
;
3408 ASSERT(t
->MinFilter
== GL_NEAREST
);
3409 return &sample_nearest_3d
;
3411 case GL_TEXTURE_CUBE_MAP
:
3413 return &sample_lambda_cube
;
3415 else if (t
->MinFilter
== GL_LINEAR
) {
3416 return &sample_linear_cube
;
3419 ASSERT(t
->MinFilter
== GL_NEAREST
);
3420 return &sample_nearest_cube
;
3422 case GL_TEXTURE_RECTANGLE_NV
:
3423 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3424 return &sample_depth_texture
;
3426 else if (needLambda
) {
3427 return &sample_lambda_rect
;
3429 else if (t
->MinFilter
== GL_LINEAR
) {
3430 return &sample_linear_rect
;
3433 ASSERT(t
->MinFilter
== GL_NEAREST
);
3434 return &sample_nearest_rect
;
3436 case GL_TEXTURE_1D_ARRAY_EXT
:
3438 return &sample_lambda_1d_array
;
3440 else if (t
->MinFilter
== GL_LINEAR
) {
3441 return &sample_linear_1d_array
;
3444 ASSERT(t
->MinFilter
== GL_NEAREST
);
3445 return &sample_nearest_1d_array
;
3447 case GL_TEXTURE_2D_ARRAY_EXT
:
3449 return &sample_lambda_2d_array
;
3451 else if (t
->MinFilter
== GL_LINEAR
) {
3452 return &sample_linear_2d_array
;
3455 ASSERT(t
->MinFilter
== GL_NEAREST
);
3456 return &sample_nearest_2d_array
;
3460 "invalid target in _swrast_choose_texture_sample_func");
3461 return &null_sample_func
;