2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2008 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 * Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
38 * see 1-pixel bands of improperly weighted linear-filtered textures.
39 * The tests/texwrap.c demo is a good test.
40 * Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
41 * Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
43 #define FRAC(f) ((f) - IFLOOR(f))
47 * Constants for integer linear interpolation.
49 #define ILERP_SCALE 65536.0F
50 #define ILERP_SHIFT 16
54 * Linear interpolation macros
56 #define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
57 #define ILERP(IT, A, B) ( (A) + (((IT) * ((B) - (A))) >> ILERP_SHIFT) )
61 * Do 2D/biliner interpolation of float values.
62 * v00, v10, v01 and v11 are typically four texture samples in a square/box.
63 * a and b are the horizontal and vertical interpolants.
64 * It's important that this function is inlined when compiled with
65 * optimization! If we find that's not true on some systems, convert
69 lerp_2d(GLfloat a
, GLfloat b
,
70 GLfloat v00
, GLfloat v10
, GLfloat v01
, GLfloat v11
)
72 const GLfloat temp0
= LERP(a
, v00
, v10
);
73 const GLfloat temp1
= LERP(a
, v01
, v11
);
74 return LERP(b
, temp0
, temp1
);
79 * Do 2D/biliner interpolation of integer values.
83 ilerp_2d(GLint ia
, GLint ib
,
84 GLint v00
, GLint v10
, GLint v01
, GLint v11
)
86 /* fixed point interpolants in [0, ILERP_SCALE] */
87 const GLint temp0
= ILERP(ia
, v00
, v10
);
88 const GLint temp1
= ILERP(ia
, v01
, v11
);
89 return ILERP(ib
, temp0
, temp1
);
94 * Do 3D/trilinear interpolation of float values.
98 lerp_3d(GLfloat a
, GLfloat b
, GLfloat c
,
99 GLfloat v000
, GLfloat v100
, GLfloat v010
, GLfloat v110
,
100 GLfloat v001
, GLfloat v101
, GLfloat v011
, GLfloat v111
)
102 const GLfloat temp00
= LERP(a
, v000
, v100
);
103 const GLfloat temp10
= LERP(a
, v010
, v110
);
104 const GLfloat temp01
= LERP(a
, v001
, v101
);
105 const GLfloat temp11
= LERP(a
, v011
, v111
);
106 const GLfloat temp0
= LERP(b
, temp00
, temp10
);
107 const GLfloat temp1
= LERP(b
, temp01
, temp11
);
108 return LERP(c
, temp0
, temp1
);
113 * Do 3D/trilinear interpolation of integer values.
117 ilerp_3d(GLint ia
, GLint ib
, GLint ic
,
118 GLint v000
, GLint v100
, GLint v010
, GLint v110
,
119 GLint v001
, GLint v101
, GLint v011
, GLint v111
)
121 /* fixed point interpolants in [0, ILERP_SCALE] */
122 const GLint temp00
= ILERP(ia
, v000
, v100
);
123 const GLint temp10
= ILERP(ia
, v010
, v110
);
124 const GLint temp01
= ILERP(ia
, v001
, v101
);
125 const GLint temp11
= ILERP(ia
, v011
, v111
);
126 const GLint temp0
= ILERP(ib
, temp00
, temp10
);
127 const GLint temp1
= ILERP(ib
, temp01
, temp11
);
128 return ILERP(ic
, temp0
, temp1
);
133 * Do linear interpolation of colors.
136 lerp_rgba(GLchan result
[4], GLfloat t
, const GLchan a
[4], const GLchan b
[4])
138 #if CHAN_TYPE == GL_FLOAT
139 result
[0] = LERP(t
, a
[0], b
[0]);
140 result
[1] = LERP(t
, a
[1], b
[1]);
141 result
[2] = LERP(t
, a
[2], b
[2]);
142 result
[3] = LERP(t
, a
[3], b
[3]);
143 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
144 result
[0] = (GLchan
) (LERP(t
, a
[0], b
[0]) + 0.5);
145 result
[1] = (GLchan
) (LERP(t
, a
[1], b
[1]) + 0.5);
146 result
[2] = (GLchan
) (LERP(t
, a
[2], b
[2]) + 0.5);
147 result
[3] = (GLchan
) (LERP(t
, a
[3], b
[3]) + 0.5);
149 /* fixed point interpolants in [0, ILERP_SCALE] */
150 const GLint it
= IROUND_POS(t
* ILERP_SCALE
);
151 ASSERT(CHAN_TYPE
== GL_UNSIGNED_BYTE
);
152 result
[0] = ILERP(it
, a
[0], b
[0]);
153 result
[1] = ILERP(it
, a
[1], b
[1]);
154 result
[2] = ILERP(it
, a
[2], b
[2]);
155 result
[3] = ILERP(it
, a
[3], b
[3]);
161 * Do bilinear interpolation of colors.
164 lerp_rgba_2d(GLchan result
[4], GLfloat a
, GLfloat b
,
165 const GLchan t00
[4], const GLchan t10
[4],
166 const GLchan t01
[4], const GLchan t11
[4])
168 #if CHAN_TYPE == GL_FLOAT
169 result
[0] = lerp_2d(a
, b
, t00
[0], t10
[0], t01
[0], t11
[0]);
170 result
[1] = lerp_2d(a
, b
, t00
[1], t10
[1], t01
[1], t11
[1]);
171 result
[2] = lerp_2d(a
, b
, t00
[2], t10
[2], t01
[2], t11
[2]);
172 result
[3] = lerp_2d(a
, b
, t00
[3], t10
[3], t01
[3], t11
[3]);
173 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
174 result
[0] = (GLchan
) (lerp_2d(a
, b
, t00
[0], t10
[0], t01
[0], t11
[0]) + 0.5);
175 result
[1] = (GLchan
) (lerp_2d(a
, b
, t00
[1], t10
[1], t01
[1], t11
[1]) + 0.5);
176 result
[2] = (GLchan
) (lerp_2d(a
, b
, t00
[2], t10
[2], t01
[2], t11
[2]) + 0.5);
177 result
[3] = (GLchan
) (lerp_2d(a
, b
, t00
[3], t10
[3], t01
[3], t11
[3]) + 0.5);
179 const GLint ia
= IROUND_POS(a
* ILERP_SCALE
);
180 const GLint ib
= IROUND_POS(b
* ILERP_SCALE
);
181 ASSERT(CHAN_TYPE
== GL_UNSIGNED_BYTE
);
182 result
[0] = ilerp_2d(ia
, ib
, t00
[0], t10
[0], t01
[0], t11
[0]);
183 result
[1] = ilerp_2d(ia
, ib
, t00
[1], t10
[1], t01
[1], t11
[1]);
184 result
[2] = ilerp_2d(ia
, ib
, t00
[2], t10
[2], t01
[2], t11
[2]);
185 result
[3] = ilerp_2d(ia
, ib
, t00
[3], t10
[3], t01
[3], t11
[3]);
191 * Do trilinear interpolation of colors.
194 lerp_rgba_3d(GLchan result
[4], GLfloat a
, GLfloat b
, GLfloat c
,
195 const GLchan t000
[4], const GLchan t100
[4],
196 const GLchan t010
[4], const GLchan t110
[4],
197 const GLchan t001
[4], const GLchan t101
[4],
198 const GLchan t011
[4], const GLchan t111
[4])
201 /* compiler should unroll these short loops */
202 #if CHAN_TYPE == GL_FLOAT
203 for (k
= 0; k
< 4; k
++) {
204 result
[k
] = lerp_3d(a
, b
, c
, t000
[k
], t100
[k
], t010
[k
], t110
[k
],
205 t001
[k
], t101
[k
], t011
[k
], t111
[k
]);
207 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
208 for (k
= 0; k
< 4; k
++) {
209 result
[k
] = (GLchan
)(lerp_3d(a
, b
, c
,
210 t000
[k
], t100
[k
], t010
[k
], t110
[k
],
211 t001
[k
], t101
[k
], t011
[k
], t111
[k
]) + 0.5F
);
214 GLint ia
= IROUND_POS(a
* ILERP_SCALE
);
215 GLint ib
= IROUND_POS(b
* ILERP_SCALE
);
216 GLint ic
= IROUND_POS(c
* ILERP_SCALE
);
217 for (k
= 0; k
< 4; k
++) {
218 result
[k
] = ilerp_3d(ia
, ib
, ic
, t000
[k
], t100
[k
], t010
[k
], t110
[k
],
219 t001
[k
], t101
[k
], t011
[k
], t111
[k
]);
226 * If A is a signed integer, A % B doesn't give the right value for A < 0
227 * (in terms of texture repeat). Just casting to unsigned fixes that.
229 #define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))
233 * Used to compute texel locations for linear sampling.
235 * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
236 * s = texcoord in [0,1]
237 * size = width (or height or depth) of texture
239 * i0, i1 = returns two nearest texel indexes
240 * weight = returns blend factor between texels
243 linear_texel_locations(GLenum wrapMode
,
244 const struct gl_texture_image
*img
,
245 GLint size
, GLfloat s
,
246 GLint
*i0
, GLint
*i1
, GLfloat
*weight
)
252 if (img
->_IsPowerOfTwo
) {
253 *i0
= IFLOOR(u
) & (size
- 1);
254 *i1
= (*i0
+ 1) & (size
- 1);
257 *i0
= REMAINDER(IFLOOR(u
), size
);
258 *i1
= REMAINDER(*i0
+ 1, size
);
261 case GL_CLAMP_TO_EDGE
:
273 if (*i1
>= (GLint
) size
)
276 case GL_CLAMP_TO_BORDER
:
278 const GLfloat min
= -1.0F
/ (2.0F
* size
);
279 const GLfloat max
= 1.0F
- min
;
291 case GL_MIRRORED_REPEAT
:
293 const GLint flr
= IFLOOR(s
);
295 u
= 1.0F
- (s
- (GLfloat
) flr
);
297 u
= s
- (GLfloat
) flr
;
298 u
= (u
* size
) - 0.5F
;
303 if (*i1
>= (GLint
) size
)
307 case GL_MIRROR_CLAMP_EXT
:
317 case GL_MIRROR_CLAMP_TO_EDGE_EXT
:
328 if (*i1
>= (GLint
) size
)
331 case GL_MIRROR_CLAMP_TO_BORDER_EXT
:
333 const GLfloat min
= -1.0F
/ (2.0F
* size
);
334 const GLfloat max
= 1.0F
- min
;
359 _mesa_problem(NULL
, "Bad wrap mode");
367 * Used to compute texel location for nearest sampling.
370 nearest_texel_location(GLenum wrapMode
,
371 const struct gl_texture_image
*img
,
372 GLint size
, GLfloat s
)
378 /* s limited to [0,1) */
379 /* i limited to [0,size-1] */
380 i
= IFLOOR(s
* size
);
381 if (img
->_IsPowerOfTwo
)
384 i
= REMAINDER(i
, size
);
386 case GL_CLAMP_TO_EDGE
:
388 /* s limited to [min,max] */
389 /* i limited to [0, size-1] */
390 const GLfloat min
= 1.0F
/ (2.0F
* size
);
391 const GLfloat max
= 1.0F
- min
;
397 i
= IFLOOR(s
* size
);
400 case GL_CLAMP_TO_BORDER
:
402 /* s limited to [min,max] */
403 /* i limited to [-1, size] */
404 const GLfloat min
= -1.0F
/ (2.0F
* size
);
405 const GLfloat max
= 1.0F
- min
;
411 i
= IFLOOR(s
* size
);
414 case GL_MIRRORED_REPEAT
:
416 const GLfloat min
= 1.0F
/ (2.0F
* size
);
417 const GLfloat max
= 1.0F
- min
;
418 const GLint flr
= IFLOOR(s
);
421 u
= 1.0F
- (s
- (GLfloat
) flr
);
423 u
= s
- (GLfloat
) flr
;
429 i
= IFLOOR(u
* size
);
432 case GL_MIRROR_CLAMP_EXT
:
434 /* s limited to [0,1] */
435 /* i limited to [0,size-1] */
436 const GLfloat u
= FABSF(s
);
442 i
= IFLOOR(u
* size
);
445 case GL_MIRROR_CLAMP_TO_EDGE_EXT
:
447 /* s limited to [min,max] */
448 /* i limited to [0, size-1] */
449 const GLfloat min
= 1.0F
/ (2.0F
* size
);
450 const GLfloat max
= 1.0F
- min
;
451 const GLfloat u
= FABSF(s
);
457 i
= IFLOOR(u
* size
);
460 case GL_MIRROR_CLAMP_TO_BORDER_EXT
:
462 /* s limited to [min,max] */
463 /* i limited to [0, size-1] */
464 const GLfloat min
= -1.0F
/ (2.0F
* size
);
465 const GLfloat max
= 1.0F
- min
;
466 const GLfloat u
= FABSF(s
);
472 i
= IFLOOR(u
* size
);
476 /* s limited to [0,1] */
477 /* i limited to [0,size-1] */
483 i
= IFLOOR(s
* size
);
486 _mesa_problem(NULL
, "Bad wrap mode");
492 /* Power of two image sizes only */
494 linear_repeat_texel_location(GLuint size
, GLfloat s
,
495 GLint
*i0
, GLint
*i1
, GLfloat
*weight
)
497 GLfloat u
= s
* size
- 0.5F
;
498 *i0
= IFLOOR(u
) & (size
- 1);
499 *i1
= (*i0
+ 1) & (size
- 1);
505 * For linear interpolation between mipmap levels N and N+1, this function
509 linear_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
512 return tObj
->BaseLevel
;
513 else if (lambda
> tObj
->_MaxLambda
)
514 return (GLint
) (tObj
->BaseLevel
+ tObj
->_MaxLambda
);
516 return (GLint
) (tObj
->BaseLevel
+ lambda
);
521 * Compute the nearest mipmap level to take texels from.
524 nearest_mipmap_level(const struct gl_texture_object
*tObj
, GLfloat lambda
)
530 else if (lambda
> tObj
->_MaxLambda
+ 0.4999F
)
531 l
= tObj
->_MaxLambda
+ 0.4999F
;
534 level
= (GLint
) (tObj
->BaseLevel
+ l
+ 0.5F
);
535 if (level
> tObj
->_MaxLevel
)
536 level
= tObj
->_MaxLevel
;
543 * Bitflags for texture border color sampling.
555 * The lambda[] array values are always monotonic. Either the whole span
556 * will be minified, magnified, or split between the two. This function
557 * determines the subranges in [0, n-1] that are to be minified or magnified.
560 compute_min_mag_ranges(const struct gl_texture_object
*tObj
,
561 GLuint n
, const GLfloat lambda
[],
562 GLuint
*minStart
, GLuint
*minEnd
,
563 GLuint
*magStart
, GLuint
*magEnd
)
565 GLfloat minMagThresh
;
567 /* we shouldn't be here if minfilter == magfilter */
568 ASSERT(tObj
->MinFilter
!= tObj
->MagFilter
);
570 /* This bit comes from the OpenGL spec: */
571 if (tObj
->MagFilter
== GL_LINEAR
572 && (tObj
->MinFilter
== GL_NEAREST_MIPMAP_NEAREST
||
573 tObj
->MinFilter
== GL_NEAREST_MIPMAP_LINEAR
)) {
581 /* DEBUG CODE: Verify that lambda[] is monotonic.
582 * We can't really use this because the inaccuracy in the LOG2 function
583 * causes this test to fail, yet the resulting texturing is correct.
587 printf("lambda delta = %g\n", lambda
[0] - lambda
[n
-1]);
588 if (lambda
[0] >= lambda
[n
-1]) { /* decreasing */
589 for (i
= 0; i
< n
- 1; i
++) {
590 ASSERT((GLint
) (lambda
[i
] * 10) >= (GLint
) (lambda
[i
+1] * 10));
593 else { /* increasing */
594 for (i
= 0; i
< n
- 1; i
++) {
595 ASSERT((GLint
) (lambda
[i
] * 10) <= (GLint
) (lambda
[i
+1] * 10));
601 if (lambda
[0] <= minMagThresh
&& (n
<= 1 || lambda
[n
-1] <= minMagThresh
)) {
602 /* magnification for whole span */
605 *minStart
= *minEnd
= 0;
607 else if (lambda
[0] > minMagThresh
&& (n
<=1 || lambda
[n
-1] > minMagThresh
)) {
608 /* minification for whole span */
611 *magStart
= *magEnd
= 0;
614 /* a mix of minification and magnification */
616 if (lambda
[0] > minMagThresh
) {
617 /* start with minification */
618 for (i
= 1; i
< n
; i
++) {
619 if (lambda
[i
] <= minMagThresh
)
628 /* start with magnification */
629 for (i
= 1; i
< n
; i
++) {
630 if (lambda
[i
] > minMagThresh
)
641 /* Verify the min/mag Start/End values
642 * We don't use this either (see above)
646 for (i
= 0; i
< n
; i
++) {
647 if (lambda
[i
] > minMagThresh
) {
649 ASSERT(i
>= *minStart
);
654 ASSERT(i
>= *magStart
);
663 /**********************************************************************/
664 /* 1-D Texture Sampling Functions */
665 /**********************************************************************/
668 * Return the texture sample for coordinate (s) using GL_NEAREST filter.
671 sample_1d_nearest(GLcontext
*ctx
,
672 const struct gl_texture_object
*tObj
,
673 const struct gl_texture_image
*img
,
674 const GLfloat texcoord
[4], GLchan rgba
[4])
676 const GLint width
= img
->Width2
; /* without border, power of two */
678 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
679 /* skip over the border, if any */
681 if (i
< 0 || i
>= (GLint
) img
->Width
) {
682 /* Need this test for GL_CLAMP_TO_BORDER mode */
683 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
686 img
->FetchTexelc(img
, i
, 0, 0, rgba
);
692 * Return the texture sample for coordinate (s) using GL_LINEAR filter.
695 sample_1d_linear(GLcontext
*ctx
,
696 const struct gl_texture_object
*tObj
,
697 const struct gl_texture_image
*img
,
698 const GLfloat texcoord
[4], GLchan rgba
[4])
700 const GLint width
= img
->Width2
;
702 GLbitfield useBorderColor
= 0x0;
704 GLchan t0
[4], t1
[4]; /* texels */
706 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
713 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
714 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
717 /* fetch texel colors */
718 if (useBorderColor
& I0BIT
) {
719 COPY_CHAN4(t0
, tObj
->_BorderChan
);
722 img
->FetchTexelc(img
, i0
, 0, 0, t0
);
724 if (useBorderColor
& I1BIT
) {
725 COPY_CHAN4(t1
, tObj
->_BorderChan
);
728 img
->FetchTexelc(img
, i1
, 0, 0, t1
);
731 lerp_rgba(rgba
, a
, t0
, t1
);
736 sample_1d_nearest_mipmap_nearest(GLcontext
*ctx
,
737 const struct gl_texture_object
*tObj
,
738 GLuint n
, const GLfloat texcoord
[][4],
739 const GLfloat lambda
[], GLchan rgba
[][4])
742 ASSERT(lambda
!= NULL
);
743 for (i
= 0; i
< n
; i
++) {
744 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
745 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
751 sample_1d_linear_mipmap_nearest(GLcontext
*ctx
,
752 const struct gl_texture_object
*tObj
,
753 GLuint n
, const GLfloat texcoord
[][4],
754 const GLfloat lambda
[], GLchan rgba
[][4])
757 ASSERT(lambda
!= NULL
);
758 for (i
= 0; i
< n
; i
++) {
759 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
760 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
766 sample_1d_nearest_mipmap_linear(GLcontext
*ctx
,
767 const struct gl_texture_object
*tObj
,
768 GLuint n
, const GLfloat texcoord
[][4],
769 const GLfloat lambda
[], GLchan rgba
[][4])
772 ASSERT(lambda
!= NULL
);
773 for (i
= 0; i
< n
; i
++) {
774 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
775 if (level
>= tObj
->_MaxLevel
) {
776 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
777 texcoord
[i
], rgba
[i
]);
781 const GLfloat f
= FRAC(lambda
[i
]);
782 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
783 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
784 lerp_rgba(rgba
[i
], f
, t0
, t1
);
791 sample_1d_linear_mipmap_linear(GLcontext
*ctx
,
792 const struct gl_texture_object
*tObj
,
793 GLuint n
, const GLfloat texcoord
[][4],
794 const GLfloat lambda
[], GLchan rgba
[][4])
797 ASSERT(lambda
!= NULL
);
798 for (i
= 0; i
< n
; i
++) {
799 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
800 if (level
>= tObj
->_MaxLevel
) {
801 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
802 texcoord
[i
], rgba
[i
]);
806 const GLfloat f
= FRAC(lambda
[i
]);
807 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
808 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
809 lerp_rgba(rgba
[i
], f
, t0
, t1
);
815 /** Sample 1D texture, nearest filtering for both min/magnification */
817 sample_nearest_1d( GLcontext
*ctx
,
818 const struct gl_texture_object
*tObj
, GLuint n
,
819 const GLfloat texcoords
[][4], const GLfloat lambda
[],
823 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
825 for (i
= 0; i
< n
; i
++) {
826 sample_1d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
831 /** Sample 1D texture, linear filtering for both min/magnification */
833 sample_linear_1d( GLcontext
*ctx
,
834 const struct gl_texture_object
*tObj
, GLuint n
,
835 const GLfloat texcoords
[][4], const GLfloat lambda
[],
839 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
841 for (i
= 0; i
< n
; i
++) {
842 sample_1d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
847 /** Sample 1D texture, using lambda to choose between min/magnification */
849 sample_lambda_1d( GLcontext
*ctx
,
850 const struct gl_texture_object
*tObj
, GLuint n
,
851 const GLfloat texcoords
[][4],
852 const GLfloat lambda
[], GLchan rgba
[][4] )
854 GLuint minStart
, minEnd
; /* texels with minification */
855 GLuint magStart
, magEnd
; /* texels with magnification */
858 ASSERT(lambda
!= NULL
);
859 compute_min_mag_ranges(tObj
, n
, lambda
,
860 &minStart
, &minEnd
, &magStart
, &magEnd
);
862 if (minStart
< minEnd
) {
863 /* do the minified texels */
864 const GLuint m
= minEnd
- minStart
;
865 switch (tObj
->MinFilter
) {
867 for (i
= minStart
; i
< minEnd
; i
++)
868 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
869 texcoords
[i
], rgba
[i
]);
872 for (i
= minStart
; i
< minEnd
; i
++)
873 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
874 texcoords
[i
], rgba
[i
]);
876 case GL_NEAREST_MIPMAP_NEAREST
:
877 sample_1d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
878 lambda
+ minStart
, rgba
+ minStart
);
880 case GL_LINEAR_MIPMAP_NEAREST
:
881 sample_1d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
882 lambda
+ minStart
, rgba
+ minStart
);
884 case GL_NEAREST_MIPMAP_LINEAR
:
885 sample_1d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
886 lambda
+ minStart
, rgba
+ minStart
);
888 case GL_LINEAR_MIPMAP_LINEAR
:
889 sample_1d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
890 lambda
+ minStart
, rgba
+ minStart
);
893 _mesa_problem(ctx
, "Bad min filter in sample_1d_texture");
898 if (magStart
< magEnd
) {
899 /* do the magnified texels */
900 switch (tObj
->MagFilter
) {
902 for (i
= magStart
; i
< magEnd
; i
++)
903 sample_1d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
904 texcoords
[i
], rgba
[i
]);
907 for (i
= magStart
; i
< magEnd
; i
++)
908 sample_1d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
909 texcoords
[i
], rgba
[i
]);
912 _mesa_problem(ctx
, "Bad mag filter in sample_1d_texture");
919 /**********************************************************************/
920 /* 2-D Texture Sampling Functions */
921 /**********************************************************************/
925 * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
928 sample_2d_nearest(GLcontext
*ctx
,
929 const struct gl_texture_object
*tObj
,
930 const struct gl_texture_image
*img
,
931 const GLfloat texcoord
[4],
934 const GLint width
= img
->Width2
; /* without border, power of two */
935 const GLint height
= img
->Height2
; /* without border, power of two */
939 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
940 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
942 /* skip over the border, if any */
946 if (i
< 0 || i
>= (GLint
) img
->Width
|| j
< 0 || j
>= (GLint
) img
->Height
) {
947 /* Need this test for GL_CLAMP_TO_BORDER mode */
948 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
951 img
->FetchTexelc(img
, i
, j
, 0, rgba
);
957 * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
958 * New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
961 sample_2d_linear(GLcontext
*ctx
,
962 const struct gl_texture_object
*tObj
,
963 const struct gl_texture_image
*img
,
964 const GLfloat texcoord
[4],
967 const GLint width
= img
->Width2
;
968 const GLint height
= img
->Height2
;
969 GLint i0
, j0
, i1
, j1
;
970 GLbitfield useBorderColor
= 0x0;
972 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
974 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
975 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
984 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
985 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
986 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
987 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
990 /* fetch four texel colors */
991 if (useBorderColor
& (I0BIT
| J0BIT
)) {
992 COPY_CHAN4(t00
, tObj
->_BorderChan
);
995 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
997 if (useBorderColor
& (I1BIT
| J0BIT
)) {
998 COPY_CHAN4(t10
, tObj
->_BorderChan
);
1001 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
1003 if (useBorderColor
& (I0BIT
| J1BIT
)) {
1004 COPY_CHAN4(t01
, tObj
->_BorderChan
);
1007 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1009 if (useBorderColor
& (I1BIT
| J1BIT
)) {
1010 COPY_CHAN4(t11
, tObj
->_BorderChan
);
1013 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1016 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
1021 * As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
1022 * We don't have to worry about the texture border.
1025 sample_2d_linear_repeat(GLcontext
*ctx
,
1026 const struct gl_texture_object
*tObj
,
1027 const struct gl_texture_image
*img
,
1028 const GLfloat texcoord
[4],
1031 const GLint width
= img
->Width2
;
1032 const GLint height
= img
->Height2
;
1033 GLint i0
, j0
, i1
, j1
;
1035 GLchan t00
[4], t10
[4], t01
[4], t11
[4]; /* sampled texel colors */
1039 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1040 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1041 ASSERT(img
->Border
== 0);
1042 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
1043 ASSERT(img
->_IsPowerOfTwo
);
1045 linear_repeat_texel_location(width
, texcoord
[0], &i0
, &i1
, &wi
);
1046 linear_repeat_texel_location(height
, texcoord
[1], &j0
, &j1
, &wj
);
1048 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
1049 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
1050 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
1051 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
1053 lerp_rgba_2d(rgba
, wi
, wj
, 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
]);
1072 sample_2d_linear_mipmap_nearest(GLcontext
*ctx
,
1073 const struct gl_texture_object
*tObj
,
1074 GLuint n
, const GLfloat texcoord
[][4],
1075 const GLfloat lambda
[], GLchan rgba
[][4])
1078 ASSERT(lambda
!= NULL
);
1079 for (i
= 0; i
< n
; i
++) {
1080 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1081 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1087 sample_2d_nearest_mipmap_linear(GLcontext
*ctx
,
1088 const struct gl_texture_object
*tObj
,
1089 GLuint n
, const GLfloat texcoord
[][4],
1090 const GLfloat lambda
[], GLchan rgba
[][4])
1093 ASSERT(lambda
!= NULL
);
1094 for (i
= 0; i
< n
; i
++) {
1095 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1096 if (level
>= tObj
->_MaxLevel
) {
1097 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1098 texcoord
[i
], rgba
[i
]);
1101 GLchan t0
[4], t1
[4]; /* texels */
1102 const GLfloat f
= FRAC(lambda
[i
]);
1103 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1104 sample_2d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1105 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1112 sample_2d_linear_mipmap_linear( GLcontext
*ctx
,
1113 const struct gl_texture_object
*tObj
,
1114 GLuint n
, const GLfloat texcoord
[][4],
1115 const GLfloat lambda
[], GLchan rgba
[][4] )
1118 ASSERT(lambda
!= NULL
);
1119 for (i
= 0; i
< n
; i
++) {
1120 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1121 if (level
>= tObj
->_MaxLevel
) {
1122 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1123 texcoord
[i
], rgba
[i
]);
1126 GLchan t0
[4], t1
[4]; /* texels */
1127 const GLfloat f
= FRAC(lambda
[i
]);
1128 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1129 sample_2d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1130 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1137 sample_2d_linear_mipmap_linear_repeat(GLcontext
*ctx
,
1138 const struct gl_texture_object
*tObj
,
1139 GLuint n
, const GLfloat texcoord
[][4],
1140 const GLfloat lambda
[], GLchan rgba
[][4])
1143 ASSERT(lambda
!= NULL
);
1144 ASSERT(tObj
->WrapS
== GL_REPEAT
);
1145 ASSERT(tObj
->WrapT
== GL_REPEAT
);
1146 for (i
= 0; i
< n
; i
++) {
1147 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1148 if (level
>= tObj
->_MaxLevel
) {
1149 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1150 texcoord
[i
], rgba
[i
]);
1153 GLchan t0
[4], t1
[4]; /* texels */
1154 const GLfloat f
= FRAC(lambda
[i
]);
1155 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
],
1157 sample_2d_linear_repeat(ctx
, tObj
, tObj
->Image
[0][level
+1],
1159 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1165 /** Sample 2D texture, nearest filtering for both min/magnification */
1167 sample_nearest_2d(GLcontext
*ctx
,
1168 const struct gl_texture_object
*tObj
, GLuint n
,
1169 const GLfloat texcoords
[][4],
1170 const GLfloat lambda
[], GLchan rgba
[][4])
1173 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1175 for (i
= 0; i
< n
; i
++) {
1176 sample_2d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1181 /** Sample 2D texture, linear filtering for both min/magnification */
1183 sample_linear_2d(GLcontext
*ctx
,
1184 const struct gl_texture_object
*tObj
, GLuint n
,
1185 const GLfloat texcoords
[][4],
1186 const GLfloat lambda
[], GLchan rgba
[][4])
1189 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1191 if (tObj
->WrapS
== GL_REPEAT
&&
1192 tObj
->WrapT
== GL_REPEAT
&&
1193 image
->_IsPowerOfTwo
&&
1194 image
->Border
== 0) {
1195 for (i
= 0; i
< n
; i
++) {
1196 sample_2d_linear_repeat(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1200 for (i
= 0; i
< n
; i
++) {
1201 sample_2d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1208 * Optimized 2-D texture sampling:
1209 * S and T wrap mode == GL_REPEAT
1210 * GL_NEAREST min/mag filter
1212 * RowStride == Width,
1216 opt_sample_rgb_2d(GLcontext
*ctx
,
1217 const struct gl_texture_object
*tObj
,
1218 GLuint n
, const GLfloat texcoords
[][4],
1219 const GLfloat lambda
[], GLchan rgba
[][4])
1221 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1222 const GLfloat width
= (GLfloat
) img
->Width
;
1223 const GLfloat height
= (GLfloat
) img
->Height
;
1224 const GLint colMask
= img
->Width
- 1;
1225 const GLint rowMask
= img
->Height
- 1;
1226 const GLint shift
= img
->WidthLog2
;
1230 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1231 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1232 ASSERT(img
->Border
==0);
1233 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGB
);
1234 ASSERT(img
->_IsPowerOfTwo
);
1236 for (k
=0; k
<n
; k
++) {
1237 GLint i
= IFLOOR(texcoords
[k
][0] * width
) & colMask
;
1238 GLint j
= IFLOOR(texcoords
[k
][1] * height
) & rowMask
;
1239 GLint pos
= (j
<< shift
) | i
;
1240 GLchan
*texel
= ((GLchan
*) img
->Data
) + 3*pos
;
1241 rgba
[k
][RCOMP
] = texel
[0];
1242 rgba
[k
][GCOMP
] = texel
[1];
1243 rgba
[k
][BCOMP
] = texel
[2];
1249 * Optimized 2-D texture sampling:
1250 * S and T wrap mode == GL_REPEAT
1251 * GL_NEAREST min/mag filter
1253 * RowStride == Width,
1257 opt_sample_rgba_2d(GLcontext
*ctx
,
1258 const struct gl_texture_object
*tObj
,
1259 GLuint n
, const GLfloat texcoords
[][4],
1260 const GLfloat lambda
[], GLchan rgba
[][4])
1262 const struct gl_texture_image
*img
= tObj
->Image
[0][tObj
->BaseLevel
];
1263 const GLfloat width
= (GLfloat
) img
->Width
;
1264 const GLfloat height
= (GLfloat
) img
->Height
;
1265 const GLint colMask
= img
->Width
- 1;
1266 const GLint rowMask
= img
->Height
- 1;
1267 const GLint shift
= img
->WidthLog2
;
1271 ASSERT(tObj
->WrapS
==GL_REPEAT
);
1272 ASSERT(tObj
->WrapT
==GL_REPEAT
);
1273 ASSERT(img
->Border
==0);
1274 ASSERT(img
->TexFormat
->MesaFormat
==MESA_FORMAT_RGBA
);
1275 ASSERT(img
->_IsPowerOfTwo
);
1277 for (i
= 0; i
< n
; i
++) {
1278 const GLint col
= IFLOOR(texcoords
[i
][0] * width
) & colMask
;
1279 const GLint row
= IFLOOR(texcoords
[i
][1] * height
) & rowMask
;
1280 const GLint pos
= (row
<< shift
) | col
;
1281 const GLchan
*texel
= ((GLchan
*) img
->Data
) + (pos
<< 2); /* pos*4 */
1282 COPY_CHAN4(rgba
[i
], texel
);
1287 /** Sample 2D texture, using lambda to choose between min/magnification */
1289 sample_lambda_2d(GLcontext
*ctx
,
1290 const struct gl_texture_object
*tObj
,
1291 GLuint n
, const GLfloat texcoords
[][4],
1292 const GLfloat lambda
[], GLchan rgba
[][4])
1294 const struct gl_texture_image
*tImg
= tObj
->Image
[0][tObj
->BaseLevel
];
1295 GLuint minStart
, minEnd
; /* texels with minification */
1296 GLuint magStart
, magEnd
; /* texels with magnification */
1298 const GLboolean repeatNoBorderPOT
= (tObj
->WrapS
== GL_REPEAT
)
1299 && (tObj
->WrapT
== GL_REPEAT
)
1300 && (tImg
->Border
== 0 && (tImg
->Width
== tImg
->RowStride
))
1301 && (tImg
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
)
1302 && tImg
->_IsPowerOfTwo
;
1304 ASSERT(lambda
!= NULL
);
1305 compute_min_mag_ranges(tObj
, n
, lambda
,
1306 &minStart
, &minEnd
, &magStart
, &magEnd
);
1308 if (minStart
< minEnd
) {
1309 /* do the minified texels */
1310 const GLuint m
= minEnd
- minStart
;
1311 switch (tObj
->MinFilter
) {
1313 if (repeatNoBorderPOT
) {
1314 switch (tImg
->TexFormat
->MesaFormat
) {
1315 case MESA_FORMAT_RGB
:
1316 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1317 NULL
, rgba
+ minStart
);
1319 case MESA_FORMAT_RGBA
:
1320 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1321 NULL
, rgba
+ minStart
);
1324 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1325 NULL
, rgba
+ minStart
);
1329 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1330 NULL
, rgba
+ minStart
);
1334 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ minStart
,
1335 NULL
, rgba
+ minStart
);
1337 case GL_NEAREST_MIPMAP_NEAREST
:
1338 sample_2d_nearest_mipmap_nearest(ctx
, tObj
, m
,
1339 texcoords
+ minStart
,
1340 lambda
+ minStart
, rgba
+ minStart
);
1342 case GL_LINEAR_MIPMAP_NEAREST
:
1343 sample_2d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1344 lambda
+ minStart
, rgba
+ minStart
);
1346 case GL_NEAREST_MIPMAP_LINEAR
:
1347 sample_2d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1348 lambda
+ minStart
, rgba
+ minStart
);
1350 case GL_LINEAR_MIPMAP_LINEAR
:
1351 if (repeatNoBorderPOT
)
1352 sample_2d_linear_mipmap_linear_repeat(ctx
, tObj
, m
,
1353 texcoords
+ minStart
, lambda
+ minStart
, rgba
+ minStart
);
1355 sample_2d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1356 lambda
+ minStart
, rgba
+ minStart
);
1359 _mesa_problem(ctx
, "Bad min filter in sample_2d_texture");
1364 if (magStart
< magEnd
) {
1365 /* do the magnified texels */
1366 const GLuint m
= magEnd
- magStart
;
1368 switch (tObj
->MagFilter
) {
1370 if (repeatNoBorderPOT
) {
1371 switch (tImg
->TexFormat
->MesaFormat
) {
1372 case MESA_FORMAT_RGB
:
1373 opt_sample_rgb_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1374 NULL
, rgba
+ magStart
);
1376 case MESA_FORMAT_RGBA
:
1377 opt_sample_rgba_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1378 NULL
, rgba
+ magStart
);
1381 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1382 NULL
, rgba
+ magStart
);
1386 sample_nearest_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1387 NULL
, rgba
+ magStart
);
1391 sample_linear_2d(ctx
, tObj
, m
, texcoords
+ magStart
,
1392 NULL
, rgba
+ magStart
);
1395 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_2d");
1402 /**********************************************************************/
1403 /* 3-D Texture Sampling Functions */
1404 /**********************************************************************/
1407 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
1410 sample_3d_nearest(GLcontext
*ctx
,
1411 const struct gl_texture_object
*tObj
,
1412 const struct gl_texture_image
*img
,
1413 const GLfloat texcoord
[4],
1416 const GLint width
= img
->Width2
; /* without border, power of two */
1417 const GLint height
= img
->Height2
; /* without border, power of two */
1418 const GLint depth
= img
->Depth2
; /* without border, power of two */
1422 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
1423 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
1424 k
= nearest_texel_location(tObj
->WrapR
, img
, depth
, texcoord
[2]);
1426 if (i
< 0 || i
>= (GLint
) img
->Width
||
1427 j
< 0 || j
>= (GLint
) img
->Height
||
1428 k
< 0 || k
>= (GLint
) img
->Depth
) {
1429 /* Need this test for GL_CLAMP_TO_BORDER mode */
1430 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
1433 img
->FetchTexelc(img
, i
, j
, k
, rgba
);
1439 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
1442 sample_3d_linear(GLcontext
*ctx
,
1443 const struct gl_texture_object
*tObj
,
1444 const struct gl_texture_image
*img
,
1445 const GLfloat texcoord
[4],
1448 const GLint width
= img
->Width2
;
1449 const GLint height
= img
->Height2
;
1450 const GLint depth
= img
->Depth2
;
1451 GLint i0
, j0
, k0
, i1
, j1
, k1
;
1452 GLbitfield useBorderColor
= 0x0;
1454 GLchan t000
[4], t010
[4], t001
[4], t011
[4];
1455 GLchan t100
[4], t110
[4], t101
[4], t111
[4];
1457 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
1458 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
1459 linear_texel_locations(tObj
->WrapR
, img
, depth
, texcoord
[2], &k0
, &k1
, &c
);
1470 /* check if sampling texture border color */
1471 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
1472 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
1473 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
1474 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
1475 if (k0
< 0 || k0
>= depth
) useBorderColor
|= K0BIT
;
1476 if (k1
< 0 || k1
>= depth
) useBorderColor
|= K1BIT
;
1480 if (useBorderColor
& (I0BIT
| J0BIT
| K0BIT
)) {
1481 COPY_CHAN4(t000
, tObj
->_BorderChan
);
1484 img
->FetchTexelc(img
, i0
, j0
, k0
, t000
);
1486 if (useBorderColor
& (I1BIT
| J0BIT
| K0BIT
)) {
1487 COPY_CHAN4(t100
, tObj
->_BorderChan
);
1490 img
->FetchTexelc(img
, i1
, j0
, k0
, t100
);
1492 if (useBorderColor
& (I0BIT
| J1BIT
| K0BIT
)) {
1493 COPY_CHAN4(t010
, tObj
->_BorderChan
);
1496 img
->FetchTexelc(img
, i0
, j1
, k0
, t010
);
1498 if (useBorderColor
& (I1BIT
| J1BIT
| K0BIT
)) {
1499 COPY_CHAN4(t110
, tObj
->_BorderChan
);
1502 img
->FetchTexelc(img
, i1
, j1
, k0
, t110
);
1505 if (useBorderColor
& (I0BIT
| J0BIT
| K1BIT
)) {
1506 COPY_CHAN4(t001
, tObj
->_BorderChan
);
1509 img
->FetchTexelc(img
, i0
, j0
, k1
, t001
);
1511 if (useBorderColor
& (I1BIT
| J0BIT
| K1BIT
)) {
1512 COPY_CHAN4(t101
, tObj
->_BorderChan
);
1515 img
->FetchTexelc(img
, i1
, j0
, k1
, t101
);
1517 if (useBorderColor
& (I0BIT
| J1BIT
| K1BIT
)) {
1518 COPY_CHAN4(t011
, tObj
->_BorderChan
);
1521 img
->FetchTexelc(img
, i0
, j1
, k1
, t011
);
1523 if (useBorderColor
& (I1BIT
| J1BIT
| K1BIT
)) {
1524 COPY_CHAN4(t111
, tObj
->_BorderChan
);
1527 img
->FetchTexelc(img
, i1
, j1
, k1
, t111
);
1530 /* trilinear interpolation of samples */
1531 lerp_rgba_3d(rgba
, a
, b
, c
, t000
, t100
, t010
, t110
, t001
, t101
, t011
, t111
);
1536 sample_3d_nearest_mipmap_nearest(GLcontext
*ctx
,
1537 const struct gl_texture_object
*tObj
,
1538 GLuint n
, const GLfloat texcoord
[][4],
1539 const GLfloat lambda
[], GLchan rgba
[][4] )
1542 for (i
= 0; i
< n
; i
++) {
1543 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1544 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1550 sample_3d_linear_mipmap_nearest(GLcontext
*ctx
,
1551 const struct gl_texture_object
*tObj
,
1552 GLuint n
, const GLfloat texcoord
[][4],
1553 const GLfloat lambda
[], GLchan rgba
[][4])
1556 ASSERT(lambda
!= NULL
);
1557 for (i
= 0; i
< n
; i
++) {
1558 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1559 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], rgba
[i
]);
1565 sample_3d_nearest_mipmap_linear(GLcontext
*ctx
,
1566 const struct gl_texture_object
*tObj
,
1567 GLuint n
, const GLfloat texcoord
[][4],
1568 const GLfloat lambda
[], GLchan rgba
[][4])
1571 ASSERT(lambda
!= NULL
);
1572 for (i
= 0; i
< n
; i
++) {
1573 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1574 if (level
>= tObj
->_MaxLevel
) {
1575 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1576 texcoord
[i
], rgba
[i
]);
1579 GLchan t0
[4], t1
[4]; /* texels */
1580 const GLfloat f
= FRAC(lambda
[i
]);
1581 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1582 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1583 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1590 sample_3d_linear_mipmap_linear(GLcontext
*ctx
,
1591 const struct gl_texture_object
*tObj
,
1592 GLuint n
, const GLfloat texcoord
[][4],
1593 const GLfloat lambda
[], GLchan rgba
[][4])
1596 ASSERT(lambda
!= NULL
);
1597 for (i
= 0; i
< n
; i
++) {
1598 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1599 if (level
>= tObj
->_MaxLevel
) {
1600 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
1601 texcoord
[i
], rgba
[i
]);
1604 GLchan t0
[4], t1
[4]; /* texels */
1605 const GLfloat f
= FRAC(lambda
[i
]);
1606 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
1607 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
1608 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1614 /** Sample 3D texture, nearest filtering for both min/magnification */
1616 sample_nearest_3d(GLcontext
*ctx
,
1617 const struct gl_texture_object
*tObj
, GLuint n
,
1618 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1622 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1624 for (i
= 0; i
< n
; i
++) {
1625 sample_3d_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1630 /** Sample 3D texture, linear filtering for both min/magnification */
1632 sample_linear_3d(GLcontext
*ctx
,
1633 const struct gl_texture_object
*tObj
, GLuint n
,
1634 const GLfloat texcoords
[][4],
1635 const GLfloat lambda
[], GLchan rgba
[][4])
1638 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
1640 for (i
= 0; i
< n
; i
++) {
1641 sample_3d_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
1646 /** Sample 3D texture, using lambda to choose between min/magnification */
1648 sample_lambda_3d(GLcontext
*ctx
,
1649 const struct gl_texture_object
*tObj
, GLuint n
,
1650 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1653 GLuint minStart
, minEnd
; /* texels with minification */
1654 GLuint magStart
, magEnd
; /* texels with magnification */
1657 ASSERT(lambda
!= NULL
);
1658 compute_min_mag_ranges(tObj
, n
, lambda
,
1659 &minStart
, &minEnd
, &magStart
, &magEnd
);
1661 if (minStart
< minEnd
) {
1662 /* do the minified texels */
1663 GLuint m
= minEnd
- minStart
;
1664 switch (tObj
->MinFilter
) {
1666 for (i
= minStart
; i
< minEnd
; i
++)
1667 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1668 texcoords
[i
], rgba
[i
]);
1671 for (i
= minStart
; i
< minEnd
; i
++)
1672 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1673 texcoords
[i
], rgba
[i
]);
1675 case GL_NEAREST_MIPMAP_NEAREST
:
1676 sample_3d_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1677 lambda
+ minStart
, rgba
+ minStart
);
1679 case GL_LINEAR_MIPMAP_NEAREST
:
1680 sample_3d_linear_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
1681 lambda
+ minStart
, rgba
+ minStart
);
1683 case GL_NEAREST_MIPMAP_LINEAR
:
1684 sample_3d_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1685 lambda
+ minStart
, rgba
+ minStart
);
1687 case GL_LINEAR_MIPMAP_LINEAR
:
1688 sample_3d_linear_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
1689 lambda
+ minStart
, rgba
+ minStart
);
1692 _mesa_problem(ctx
, "Bad min filter in sample_3d_texture");
1697 if (magStart
< magEnd
) {
1698 /* do the magnified texels */
1699 switch (tObj
->MagFilter
) {
1701 for (i
= magStart
; i
< magEnd
; i
++)
1702 sample_3d_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1703 texcoords
[i
], rgba
[i
]);
1706 for (i
= magStart
; i
< magEnd
; i
++)
1707 sample_3d_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
1708 texcoords
[i
], rgba
[i
]);
1711 _mesa_problem(ctx
, "Bad mag filter in sample_3d_texture");
1718 /**********************************************************************/
1719 /* Texture Cube Map Sampling Functions */
1720 /**********************************************************************/
1723 * Choose one of six sides of a texture cube map given the texture
1724 * coord (rx,ry,rz). Return pointer to corresponding array of texture
1727 static const struct gl_texture_image
**
1728 choose_cube_face(const struct gl_texture_object
*texObj
,
1729 const GLfloat texcoord
[4], GLfloat newCoord
[4])
1733 direction target sc tc ma
1734 ---------- ------------------------------- --- --- ---
1735 +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
1736 -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
1737 +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
1738 -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
1739 +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
1740 -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
1742 const GLfloat rx
= texcoord
[0];
1743 const GLfloat ry
= texcoord
[1];
1744 const GLfloat rz
= texcoord
[2];
1745 const GLfloat arx
= FABSF(rx
), ary
= FABSF(ry
), arz
= FABSF(rz
);
1749 if (arx
> ary
&& arx
> arz
) {
1763 else if (ary
> arx
&& ary
> arz
) {
1792 newCoord
[0] = ( sc
/ ma
+ 1.0F
) * 0.5F
;
1793 newCoord
[1] = ( tc
/ ma
+ 1.0F
) * 0.5F
;
1794 return (const struct gl_texture_image
**) texObj
->Image
[face
];
1799 sample_nearest_cube(GLcontext
*ctx
,
1800 const struct gl_texture_object
*tObj
, GLuint n
,
1801 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1806 for (i
= 0; i
< n
; i
++) {
1807 const struct gl_texture_image
**images
;
1808 GLfloat newCoord
[4];
1809 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1810 sample_2d_nearest(ctx
, tObj
, images
[tObj
->BaseLevel
],
1817 sample_linear_cube(GLcontext
*ctx
,
1818 const struct gl_texture_object
*tObj
, GLuint n
,
1819 const GLfloat texcoords
[][4],
1820 const GLfloat lambda
[], GLchan rgba
[][4])
1824 for (i
= 0; i
< n
; i
++) {
1825 const struct gl_texture_image
**images
;
1826 GLfloat newCoord
[4];
1827 images
= choose_cube_face(tObj
, texcoords
[i
], newCoord
);
1828 sample_2d_linear(ctx
, tObj
, images
[tObj
->BaseLevel
],
1835 sample_cube_nearest_mipmap_nearest(GLcontext
*ctx
,
1836 const struct gl_texture_object
*tObj
,
1837 GLuint n
, const GLfloat texcoord
[][4],
1838 const GLfloat lambda
[], GLchan rgba
[][4])
1841 ASSERT(lambda
!= NULL
);
1842 for (i
= 0; i
< n
; i
++) {
1843 const struct gl_texture_image
**images
;
1844 GLfloat newCoord
[4];
1846 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1848 /* XXX we actually need to recompute lambda here based on the newCoords.
1849 * But we would need the texcoords of adjacent fragments to compute that
1850 * properly, and we don't have those here.
1851 * For now, do an approximation: subtracting 1 from the chosen mipmap
1852 * level seems to work in some test cases.
1853 * The same adjustment is done in the next few functions.
1855 level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1856 level
= MAX2(level
- 1, 0);
1858 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1864 sample_cube_linear_mipmap_nearest(GLcontext
*ctx
,
1865 const struct gl_texture_object
*tObj
,
1866 GLuint n
, const GLfloat texcoord
[][4],
1867 const GLfloat lambda
[], GLchan rgba
[][4])
1870 ASSERT(lambda
!= NULL
);
1871 for (i
= 0; i
< n
; i
++) {
1872 const struct gl_texture_image
**images
;
1873 GLfloat newCoord
[4];
1874 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
1875 level
= MAX2(level
- 1, 0); /* see comment above */
1876 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1877 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, rgba
[i
]);
1883 sample_cube_nearest_mipmap_linear(GLcontext
*ctx
,
1884 const struct gl_texture_object
*tObj
,
1885 GLuint n
, const GLfloat texcoord
[][4],
1886 const GLfloat lambda
[], GLchan rgba
[][4])
1889 ASSERT(lambda
!= NULL
);
1890 for (i
= 0; i
< n
; i
++) {
1891 const struct gl_texture_image
**images
;
1892 GLfloat newCoord
[4];
1893 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1894 level
= MAX2(level
- 1, 0); /* see comment above */
1895 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1896 if (level
>= tObj
->_MaxLevel
) {
1897 sample_2d_nearest(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1901 GLchan t0
[4], t1
[4]; /* texels */
1902 const GLfloat f
= FRAC(lambda
[i
]);
1903 sample_2d_nearest(ctx
, tObj
, images
[level
], newCoord
, t0
);
1904 sample_2d_nearest(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1905 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1912 sample_cube_linear_mipmap_linear(GLcontext
*ctx
,
1913 const struct gl_texture_object
*tObj
,
1914 GLuint n
, const GLfloat texcoord
[][4],
1915 const GLfloat lambda
[], GLchan rgba
[][4])
1918 ASSERT(lambda
!= NULL
);
1919 for (i
= 0; i
< n
; i
++) {
1920 const struct gl_texture_image
**images
;
1921 GLfloat newCoord
[4];
1922 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
1923 level
= MAX2(level
- 1, 0); /* see comment above */
1924 images
= choose_cube_face(tObj
, texcoord
[i
], newCoord
);
1925 if (level
>= tObj
->_MaxLevel
) {
1926 sample_2d_linear(ctx
, tObj
, images
[tObj
->_MaxLevel
],
1930 GLchan t0
[4], t1
[4];
1931 const GLfloat f
= FRAC(lambda
[i
]);
1932 sample_2d_linear(ctx
, tObj
, images
[level
], newCoord
, t0
);
1933 sample_2d_linear(ctx
, tObj
, images
[level
+1], newCoord
, t1
);
1934 lerp_rgba(rgba
[i
], f
, t0
, t1
);
1940 /** Sample cube texture, using lambda to choose between min/magnification */
1942 sample_lambda_cube(GLcontext
*ctx
,
1943 const struct gl_texture_object
*tObj
, GLuint n
,
1944 const GLfloat texcoords
[][4], const GLfloat lambda
[],
1947 GLuint minStart
, minEnd
; /* texels with minification */
1948 GLuint magStart
, magEnd
; /* texels with magnification */
1950 ASSERT(lambda
!= NULL
);
1951 compute_min_mag_ranges(tObj
, n
, lambda
,
1952 &minStart
, &minEnd
, &magStart
, &magEnd
);
1954 if (minStart
< minEnd
) {
1955 /* do the minified texels */
1956 const GLuint m
= minEnd
- minStart
;
1957 switch (tObj
->MinFilter
) {
1959 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1960 lambda
+ minStart
, rgba
+ minStart
);
1963 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ minStart
,
1964 lambda
+ minStart
, rgba
+ minStart
);
1966 case GL_NEAREST_MIPMAP_NEAREST
:
1967 sample_cube_nearest_mipmap_nearest(ctx
, tObj
, m
,
1968 texcoords
+ minStart
,
1969 lambda
+ minStart
, rgba
+ minStart
);
1971 case GL_LINEAR_MIPMAP_NEAREST
:
1972 sample_cube_linear_mipmap_nearest(ctx
, tObj
, m
,
1973 texcoords
+ minStart
,
1974 lambda
+ minStart
, rgba
+ minStart
);
1976 case GL_NEAREST_MIPMAP_LINEAR
:
1977 sample_cube_nearest_mipmap_linear(ctx
, tObj
, m
,
1978 texcoords
+ minStart
,
1979 lambda
+ minStart
, rgba
+ minStart
);
1981 case GL_LINEAR_MIPMAP_LINEAR
:
1982 sample_cube_linear_mipmap_linear(ctx
, tObj
, m
,
1983 texcoords
+ minStart
,
1984 lambda
+ minStart
, rgba
+ minStart
);
1987 _mesa_problem(ctx
, "Bad min filter in sample_lambda_cube");
1991 if (magStart
< magEnd
) {
1992 /* do the magnified texels */
1993 const GLuint m
= magEnd
- magStart
;
1994 switch (tObj
->MagFilter
) {
1996 sample_nearest_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
1997 lambda
+ magStart
, rgba
+ magStart
);
2000 sample_linear_cube(ctx
, tObj
, m
, texcoords
+ magStart
,
2001 lambda
+ magStart
, rgba
+ magStart
);
2004 _mesa_problem(ctx
, "Bad mag filter in sample_lambda_cube");
2010 /**********************************************************************/
2011 /* Texture Rectangle Sampling Functions */
2012 /**********************************************************************/
2016 * Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
2019 clamp_rect_coord_nearest(GLenum wrapMode
, GLfloat coord
, GLint max
)
2023 return IFLOOR( CLAMP(coord
, 0.0F
, max
- 1) );
2024 case GL_CLAMP_TO_EDGE
:
2025 return IFLOOR( CLAMP(coord
, 0.5F
, max
- 0.5F
) );
2026 case GL_CLAMP_TO_BORDER
:
2027 return IFLOOR( CLAMP(coord
, -0.5F
, max
+ 0.5F
) );
2029 _mesa_problem(NULL
, "bad wrapMode in clamp_rect_coord_nearest");
2036 * As above, but GL_LINEAR filtering.
2039 clamp_rect_coord_linear(GLenum wrapMode
, GLfloat coord
, GLint max
,
2040 GLint
*i0out
, GLint
*i1out
, GLfloat
*weight
)
2046 /* Not exactly what the spec says, but it matches NVIDIA output */
2047 fcol
= CLAMP(coord
- 0.5F
, 0.0, max
-1);
2051 case GL_CLAMP_TO_EDGE
:
2052 fcol
= CLAMP(coord
, 0.5F
, max
- 0.5F
);
2059 case GL_CLAMP_TO_BORDER
:
2060 fcol
= CLAMP(coord
, -0.5F
, max
+ 0.5F
);
2065 _mesa_problem(NULL
, "bad wrapMode in clamp_rect_coord_linear");
2071 *weight
= FRAC(fcol
);
2076 sample_nearest_rect(GLcontext
*ctx
,
2077 const struct gl_texture_object
*tObj
, GLuint n
,
2078 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2081 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2082 const GLint width
= img
->Width
;
2083 const GLint height
= img
->Height
;
2089 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2090 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2091 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2092 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2093 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2094 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2095 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2097 for (i
= 0; i
< n
; i
++) {
2099 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2100 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2101 if (col
< 0 || col
>= width
|| row
< 0 || row
>= height
)
2102 COPY_CHAN4(rgba
[i
], tObj
->_BorderChan
);
2104 img
->FetchTexelc(img
, col
, row
, 0, rgba
[i
]);
2110 sample_linear_rect(GLcontext
*ctx
,
2111 const struct gl_texture_object
*tObj
, GLuint n
,
2112 const GLfloat texcoords
[][4],
2113 const GLfloat lambda
[], GLchan rgba
[][4])
2115 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2116 const GLint width
= img
->Width
;
2117 const GLint height
= img
->Height
;
2123 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2124 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2125 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2126 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2127 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2128 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2129 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2131 for (i
= 0; i
< n
; i
++) {
2132 GLint i0
, j0
, i1
, j1
;
2133 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2135 GLbitfield useBorderColor
= 0x0;
2137 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0], width
,
2139 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1], height
,
2142 /* compute integer rows/columns */
2143 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2144 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2145 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2146 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2148 /* get four texel samples */
2149 if (useBorderColor
& (I0BIT
| J0BIT
))
2150 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2152 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
2154 if (useBorderColor
& (I1BIT
| J0BIT
))
2155 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2157 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
2159 if (useBorderColor
& (I0BIT
| J1BIT
))
2160 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2162 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
2164 if (useBorderColor
& (I1BIT
| J1BIT
))
2165 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2167 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
2169 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2174 /** Sample Rect texture, using lambda to choose between min/magnification */
2176 sample_lambda_rect(GLcontext
*ctx
,
2177 const struct gl_texture_object
*tObj
, GLuint n
,
2178 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2181 GLuint minStart
, minEnd
, magStart
, magEnd
;
2183 /* We only need lambda to decide between minification and magnification.
2184 * There is no mipmapping with rectangular textures.
2186 compute_min_mag_ranges(tObj
, n
, lambda
,
2187 &minStart
, &minEnd
, &magStart
, &magEnd
);
2189 if (minStart
< minEnd
) {
2190 if (tObj
->MinFilter
== GL_NEAREST
) {
2191 sample_nearest_rect(ctx
, tObj
, minEnd
- minStart
,
2192 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2195 sample_linear_rect(ctx
, tObj
, minEnd
- minStart
,
2196 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2199 if (magStart
< magEnd
) {
2200 if (tObj
->MagFilter
== GL_NEAREST
) {
2201 sample_nearest_rect(ctx
, tObj
, magEnd
- magStart
,
2202 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2205 sample_linear_rect(ctx
, tObj
, magEnd
- magStart
,
2206 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2213 /**********************************************************************/
2214 /* 2D Texture Array Sampling Functions */
2215 /**********************************************************************/
2218 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2221 sample_2d_array_nearest(GLcontext
*ctx
,
2222 const struct gl_texture_object
*tObj
,
2223 const struct gl_texture_image
*img
,
2224 const GLfloat texcoord
[4],
2227 const GLint width
= img
->Width2
; /* without border, power of two */
2228 const GLint height
= img
->Height2
; /* without border, power of two */
2229 const GLint depth
= img
->Depth
;
2234 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2235 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
2236 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2238 if (i
< 0 || i
>= (GLint
) img
->Width
||
2239 j
< 0 || j
>= (GLint
) img
->Height
||
2240 array
< 0 || array
>= (GLint
) img
->Depth
) {
2241 /* Need this test for GL_CLAMP_TO_BORDER mode */
2242 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2245 img
->FetchTexelc(img
, i
, j
, array
, rgba
);
2251 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2254 sample_2d_array_linear(GLcontext
*ctx
,
2255 const struct gl_texture_object
*tObj
,
2256 const struct gl_texture_image
*img
,
2257 const GLfloat texcoord
[4],
2260 const GLint width
= img
->Width2
;
2261 const GLint height
= img
->Height2
;
2262 const GLint depth
= img
->Depth
;
2263 GLint i0
, j0
, i1
, j1
;
2265 GLbitfield useBorderColor
= 0x0;
2267 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2269 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2270 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
2271 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2273 if (array
< 0 || array
>= depth
) {
2274 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2284 /* check if sampling texture border color */
2285 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2286 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2287 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2288 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2292 if (useBorderColor
& (I0BIT
| J0BIT
)) {
2293 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2296 img
->FetchTexelc(img
, i0
, j0
, array
, t00
);
2298 if (useBorderColor
& (I1BIT
| J0BIT
)) {
2299 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2302 img
->FetchTexelc(img
, i1
, j0
, array
, t10
);
2304 if (useBorderColor
& (I0BIT
| J1BIT
)) {
2305 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2308 img
->FetchTexelc(img
, i0
, j1
, array
, t01
);
2310 if (useBorderColor
& (I1BIT
| J1BIT
)) {
2311 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2314 img
->FetchTexelc(img
, i1
, j1
, array
, t11
);
2317 /* trilinear interpolation of samples */
2318 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
2324 sample_2d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2325 const struct gl_texture_object
*tObj
,
2326 GLuint n
, const GLfloat texcoord
[][4],
2327 const GLfloat lambda
[], GLchan rgba
[][4])
2330 for (i
= 0; i
< n
; i
++) {
2331 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2332 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2339 sample_2d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2340 const struct gl_texture_object
*tObj
,
2341 GLuint n
, const GLfloat texcoord
[][4],
2342 const GLfloat lambda
[], GLchan rgba
[][4])
2345 ASSERT(lambda
!= NULL
);
2346 for (i
= 0; i
< n
; i
++) {
2347 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2348 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2349 texcoord
[i
], rgba
[i
]);
2355 sample_2d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2356 const struct gl_texture_object
*tObj
,
2357 GLuint n
, const GLfloat texcoord
[][4],
2358 const GLfloat lambda
[], GLchan rgba
[][4])
2361 ASSERT(lambda
!= NULL
);
2362 for (i
= 0; i
< n
; i
++) {
2363 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2364 if (level
>= tObj
->_MaxLevel
) {
2365 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2366 texcoord
[i
], rgba
[i
]);
2369 GLchan t0
[4], t1
[4]; /* texels */
2370 const GLfloat f
= FRAC(lambda
[i
]);
2371 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
],
2373 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1],
2375 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2382 sample_2d_array_linear_mipmap_linear(GLcontext
*ctx
,
2383 const struct gl_texture_object
*tObj
,
2384 GLuint n
, const GLfloat texcoord
[][4],
2385 const GLfloat lambda
[], GLchan rgba
[][4])
2388 ASSERT(lambda
!= NULL
);
2389 for (i
= 0; i
< n
; i
++) {
2390 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2391 if (level
>= tObj
->_MaxLevel
) {
2392 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2393 texcoord
[i
], rgba
[i
]);
2396 GLchan t0
[4], t1
[4]; /* texels */
2397 const GLfloat f
= FRAC(lambda
[i
]);
2398 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2400 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1],
2402 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2408 /** Sample 2D Array texture, nearest filtering for both min/magnification */
2410 sample_nearest_2d_array(GLcontext
*ctx
,
2411 const struct gl_texture_object
*tObj
, GLuint n
,
2412 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2416 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2418 for (i
= 0; i
< n
; i
++) {
2419 sample_2d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2425 /** Sample 2D Array texture, linear filtering for both min/magnification */
2427 sample_linear_2d_array(GLcontext
*ctx
,
2428 const struct gl_texture_object
*tObj
, GLuint n
,
2429 const GLfloat texcoords
[][4],
2430 const GLfloat lambda
[], GLchan rgba
[][4])
2433 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2435 for (i
= 0; i
< n
; i
++) {
2436 sample_2d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2441 /** Sample 2D Array texture, using lambda to choose between min/magnification */
2443 sample_lambda_2d_array(GLcontext
*ctx
,
2444 const struct gl_texture_object
*tObj
, GLuint n
,
2445 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2448 GLuint minStart
, minEnd
; /* texels with minification */
2449 GLuint magStart
, magEnd
; /* texels with magnification */
2452 ASSERT(lambda
!= NULL
);
2453 compute_min_mag_ranges(tObj
, n
, lambda
,
2454 &minStart
, &minEnd
, &magStart
, &magEnd
);
2456 if (minStart
< minEnd
) {
2457 /* do the minified texels */
2458 GLuint m
= minEnd
- minStart
;
2459 switch (tObj
->MinFilter
) {
2461 for (i
= minStart
; i
< minEnd
; i
++)
2462 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2463 texcoords
[i
], rgba
[i
]);
2466 for (i
= minStart
; i
< minEnd
; i
++)
2467 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2468 texcoords
[i
], rgba
[i
]);
2470 case GL_NEAREST_MIPMAP_NEAREST
:
2471 sample_2d_array_nearest_mipmap_nearest(ctx
, tObj
, m
,
2472 texcoords
+ minStart
,
2476 case GL_LINEAR_MIPMAP_NEAREST
:
2477 sample_2d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2478 texcoords
+ minStart
,
2482 case GL_NEAREST_MIPMAP_LINEAR
:
2483 sample_2d_array_nearest_mipmap_linear(ctx
, tObj
, m
,
2484 texcoords
+ minStart
,
2488 case GL_LINEAR_MIPMAP_LINEAR
:
2489 sample_2d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2490 texcoords
+ minStart
,
2495 _mesa_problem(ctx
, "Bad min filter in sample_2d_array_texture");
2500 if (magStart
< magEnd
) {
2501 /* do the magnified texels */
2502 switch (tObj
->MagFilter
) {
2504 for (i
= magStart
; i
< magEnd
; i
++)
2505 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2506 texcoords
[i
], rgba
[i
]);
2509 for (i
= magStart
; i
< magEnd
; i
++)
2510 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2511 texcoords
[i
], rgba
[i
]);
2514 _mesa_problem(ctx
, "Bad mag filter in sample_2d_array_texture");
2523 /**********************************************************************/
2524 /* 1D Texture Array Sampling Functions */
2525 /**********************************************************************/
2528 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2531 sample_1d_array_nearest(GLcontext
*ctx
,
2532 const struct gl_texture_object
*tObj
,
2533 const struct gl_texture_image
*img
,
2534 const GLfloat texcoord
[4],
2537 const GLint width
= img
->Width2
; /* without border, power of two */
2538 const GLint height
= img
->Height
;
2543 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2544 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2546 if (i
< 0 || i
>= (GLint
) img
->Width
||
2547 array
< 0 || array
>= (GLint
) img
->Height
) {
2548 /* Need this test for GL_CLAMP_TO_BORDER mode */
2549 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2552 img
->FetchTexelc(img
, i
, array
, 0, rgba
);
2558 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2561 sample_1d_array_linear(GLcontext
*ctx
,
2562 const struct gl_texture_object
*tObj
,
2563 const struct gl_texture_image
*img
,
2564 const GLfloat texcoord
[4],
2567 const GLint width
= img
->Width2
;
2568 const GLint height
= img
->Height
;
2571 GLbitfield useBorderColor
= 0x0;
2573 GLchan t0
[4], t1
[4];
2575 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2576 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2583 /* check if sampling texture border color */
2584 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2585 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2588 if (array
< 0 || array
>= height
) useBorderColor
|= K0BIT
;
2591 if (useBorderColor
& (I0BIT
| K0BIT
)) {
2592 COPY_CHAN4(t0
, tObj
->_BorderChan
);
2595 img
->FetchTexelc(img
, i0
, array
, 0, t0
);
2597 if (useBorderColor
& (I1BIT
| K0BIT
)) {
2598 COPY_CHAN4(t1
, tObj
->_BorderChan
);
2601 img
->FetchTexelc(img
, i1
, array
, 0, t1
);
2604 /* bilinear interpolation of samples */
2605 lerp_rgba(rgba
, a
, t0
, t1
);
2610 sample_1d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2611 const struct gl_texture_object
*tObj
,
2612 GLuint n
, const GLfloat texcoord
[][4],
2613 const GLfloat lambda
[], GLchan rgba
[][4])
2616 for (i
= 0; i
< n
; i
++) {
2617 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2618 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2625 sample_1d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2626 const struct gl_texture_object
*tObj
,
2627 GLuint n
, const GLfloat texcoord
[][4],
2628 const GLfloat lambda
[], GLchan rgba
[][4])
2631 ASSERT(lambda
!= NULL
);
2632 for (i
= 0; i
< n
; i
++) {
2633 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2634 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2635 texcoord
[i
], rgba
[i
]);
2641 sample_1d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2642 const struct gl_texture_object
*tObj
,
2643 GLuint n
, const GLfloat texcoord
[][4],
2644 const GLfloat lambda
[], GLchan rgba
[][4])
2647 ASSERT(lambda
!= NULL
);
2648 for (i
= 0; i
< n
; i
++) {
2649 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2650 if (level
>= tObj
->_MaxLevel
) {
2651 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2652 texcoord
[i
], rgba
[i
]);
2655 GLchan t0
[4], t1
[4]; /* texels */
2656 const GLfloat f
= FRAC(lambda
[i
]);
2657 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2658 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2659 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2666 sample_1d_array_linear_mipmap_linear(GLcontext
*ctx
,
2667 const struct gl_texture_object
*tObj
,
2668 GLuint n
, const GLfloat texcoord
[][4],
2669 const GLfloat lambda
[], GLchan rgba
[][4])
2672 ASSERT(lambda
!= NULL
);
2673 for (i
= 0; i
< n
; i
++) {
2674 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2675 if (level
>= tObj
->_MaxLevel
) {
2676 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2677 texcoord
[i
], rgba
[i
]);
2680 GLchan t0
[4], t1
[4]; /* texels */
2681 const GLfloat f
= FRAC(lambda
[i
]);
2682 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2683 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2684 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2690 /** Sample 1D Array texture, nearest filtering for both min/magnification */
2692 sample_nearest_1d_array(GLcontext
*ctx
,
2693 const struct gl_texture_object
*tObj
, GLuint n
,
2694 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2698 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2700 for (i
= 0; i
< n
; i
++) {
2701 sample_1d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2706 /** Sample 1D Array texture, linear filtering for both min/magnification */
2708 sample_linear_1d_array(GLcontext
*ctx
,
2709 const struct gl_texture_object
*tObj
, GLuint n
,
2710 const GLfloat texcoords
[][4],
2711 const GLfloat lambda
[], GLchan rgba
[][4])
2714 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2716 for (i
= 0; i
< n
; i
++) {
2717 sample_1d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2722 /** Sample 1D Array texture, using lambda to choose between min/magnification */
2724 sample_lambda_1d_array(GLcontext
*ctx
,
2725 const struct gl_texture_object
*tObj
, GLuint n
,
2726 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2729 GLuint minStart
, minEnd
; /* texels with minification */
2730 GLuint magStart
, magEnd
; /* texels with magnification */
2733 ASSERT(lambda
!= NULL
);
2734 compute_min_mag_ranges(tObj
, n
, lambda
,
2735 &minStart
, &minEnd
, &magStart
, &magEnd
);
2737 if (minStart
< minEnd
) {
2738 /* do the minified texels */
2739 GLuint m
= minEnd
- minStart
;
2740 switch (tObj
->MinFilter
) {
2742 for (i
= minStart
; i
< minEnd
; i
++)
2743 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2744 texcoords
[i
], rgba
[i
]);
2747 for (i
= minStart
; i
< minEnd
; i
++)
2748 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2749 texcoords
[i
], rgba
[i
]);
2751 case GL_NEAREST_MIPMAP_NEAREST
:
2752 sample_1d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2753 lambda
+ minStart
, rgba
+ minStart
);
2755 case GL_LINEAR_MIPMAP_NEAREST
:
2756 sample_1d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2757 texcoords
+ minStart
,
2761 case GL_NEAREST_MIPMAP_LINEAR
:
2762 sample_1d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2763 lambda
+ minStart
, rgba
+ minStart
);
2765 case GL_LINEAR_MIPMAP_LINEAR
:
2766 sample_1d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2767 texcoords
+ minStart
,
2772 _mesa_problem(ctx
, "Bad min filter in sample_1d_array_texture");
2777 if (magStart
< magEnd
) {
2778 /* do the magnified texels */
2779 switch (tObj
->MagFilter
) {
2781 for (i
= magStart
; i
< magEnd
; i
++)
2782 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2783 texcoords
[i
], rgba
[i
]);
2786 for (i
= magStart
; i
< magEnd
; i
++)
2787 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2788 texcoords
[i
], rgba
[i
]);
2791 _mesa_problem(ctx
, "Bad mag filter in sample_1d_array_texture");
2799 * Sample a shadow/depth texture.
2802 sample_depth_texture( GLcontext
*ctx
,
2803 const struct gl_texture_object
*tObj
, GLuint n
,
2804 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2807 const GLint baseLevel
= tObj
->BaseLevel
;
2808 const struct gl_texture_image
*img
= tObj
->Image
[0][baseLevel
];
2809 const GLint width
= img
->Width
;
2810 const GLint height
= img
->Height
;
2811 const GLint depth
= img
->Depth
;
2812 const GLuint compare_coord
= (tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
)
2820 ASSERT(img
->TexFormat
->BaseFormat
== GL_DEPTH_COMPONENT
||
2821 img
->TexFormat
->BaseFormat
== GL_DEPTH_STENCIL_EXT
);
2823 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
2824 tObj
->Target
== GL_TEXTURE_2D
||
2825 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
||
2826 tObj
->Target
== GL_TEXTURE_1D_ARRAY_EXT
||
2827 tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
);
2829 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2831 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2833 function
= tObj
->_Function
;
2834 if (tObj
->MagFilter
== GL_NEAREST
) {
2836 for (i
= 0; i
< n
; i
++) {
2837 GLfloat depthSample
;
2838 GLint col
, row
, slice
;
2840 switch (tObj
->Target
) {
2841 case GL_TEXTURE_RECTANGLE_ARB
:
2842 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2843 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2848 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2855 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2857 row
= nearest_texel_location(tObj
->WrapT
, img
, height
,
2862 case GL_TEXTURE_1D_ARRAY_EXT
:
2863 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2865 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2869 case GL_TEXTURE_2D_ARRAY_EXT
:
2870 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2872 row
= nearest_texel_location(tObj
->WrapT
, img
, height
,
2874 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2877 col
= row
= slice
= 0;
2880 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
&&
2881 slice
>= 0 && slice
< depth
) {
2882 img
->FetchTexelf(img
, col
, row
, slice
, &depthSample
);
2885 depthSample
= tObj
->BorderColor
[0];
2890 result
= (texcoords
[i
][compare_coord
] <= depthSample
) ? CHAN_MAX
: ambient
;
2893 result
= (texcoords
[i
][compare_coord
] >= depthSample
) ? CHAN_MAX
: ambient
;
2896 result
= (texcoords
[i
][compare_coord
] < depthSample
) ? CHAN_MAX
: ambient
;
2899 result
= (texcoords
[i
][compare_coord
] > depthSample
) ? CHAN_MAX
: ambient
;
2902 result
= (texcoords
[i
][compare_coord
] == depthSample
) ? CHAN_MAX
: ambient
;
2905 result
= (texcoords
[i
][compare_coord
] != depthSample
) ? CHAN_MAX
: ambient
;
2914 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2917 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2921 switch (tObj
->DepthMode
) {
2923 texel
[i
][RCOMP
] = result
;
2924 texel
[i
][GCOMP
] = result
;
2925 texel
[i
][BCOMP
] = result
;
2926 texel
[i
][ACOMP
] = CHAN_MAX
;
2929 texel
[i
][RCOMP
] = result
;
2930 texel
[i
][GCOMP
] = result
;
2931 texel
[i
][BCOMP
] = result
;
2932 texel
[i
][ACOMP
] = result
;
2935 texel
[i
][RCOMP
] = 0;
2936 texel
[i
][GCOMP
] = 0;
2937 texel
[i
][BCOMP
] = 0;
2938 texel
[i
][ACOMP
] = result
;
2941 _mesa_problem(ctx
, "Bad depth texture mode");
2947 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
2948 for (i
= 0; i
< n
; i
++) {
2949 GLfloat depth00
, depth01
, depth10
, depth11
;
2950 GLint i0
, i1
, j0
, j1
;
2953 GLuint useBorderTexel
;
2955 switch (tObj
->Target
) {
2956 case GL_TEXTURE_RECTANGLE_ARB
:
2957 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0],
2958 width
, &i0
, &i1
, &a
);
2959 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1],
2960 height
, &j0
, &j1
, &b
);
2966 linear_texel_locations(tObj
->WrapS
, img
, width
,
2967 texcoords
[i
][0], &i0
, &i1
, &a
);
2968 linear_texel_locations(tObj
->WrapT
, img
, height
,
2969 texcoords
[i
][1], &j0
, &j1
, &b
);
2973 case GL_TEXTURE_1D_ARRAY_EXT
:
2974 linear_texel_locations(tObj
->WrapS
, img
, width
,
2975 texcoords
[i
][0], &i0
, &i1
, &a
);
2976 j0
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2981 case GL_TEXTURE_2D_ARRAY_EXT
:
2982 linear_texel_locations(tObj
->WrapS
, img
, width
,
2983 texcoords
[i
][0], &i0
, &i1
, &a
);
2984 linear_texel_locations(tObj
->WrapT
, img
, height
,
2985 texcoords
[i
][1], &j0
, &j1
, &b
);
2986 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2996 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3002 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
3003 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
3004 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
3005 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
3008 if (slice
< 0 || slice
>= (GLint
) depth
) {
3009 depth00
= tObj
->BorderColor
[0];
3010 depth01
= tObj
->BorderColor
[0];
3011 depth10
= tObj
->BorderColor
[0];
3012 depth11
= tObj
->BorderColor
[0];
3015 /* get four depth samples from the texture */
3016 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
3017 depth00
= tObj
->BorderColor
[0];
3020 img
->FetchTexelf(img
, i0
, j0
, slice
, &depth00
);
3022 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
3023 depth10
= tObj
->BorderColor
[0];
3026 img
->FetchTexelf(img
, i1
, j0
, slice
, &depth10
);
3029 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3030 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
3031 depth01
= tObj
->BorderColor
[0];
3034 img
->FetchTexelf(img
, i0
, j1
, slice
, &depth01
);
3036 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
3037 depth11
= tObj
->BorderColor
[0];
3040 img
->FetchTexelf(img
, i1
, j1
, slice
, &depth11
);
3050 /* compute a single weighted depth sample and do one comparison */
3051 const GLfloat depthSample
3052 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3053 if ((depthSample
<= texcoords
[i
][compare_coord
] && function
== GL_LEQUAL
) ||
3054 (depthSample
>= texcoords
[i
][compare_coord
] && function
== GL_GEQUAL
)) {
3062 /* Do four depth/R comparisons and compute a weighted result.
3063 * If this touches on somebody's I.P., I'll remove this code
3066 const GLfloat d
= (CHAN_MAXF
- (GLfloat
) ambient
) * 0.25F
;
3067 GLfloat luminance
= CHAN_MAXF
;
3071 if (depth00
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3072 if (depth01
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3073 if (depth10
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3074 if (depth11
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3075 result
= (GLchan
) luminance
;
3078 if (depth00
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3079 if (depth01
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3080 if (depth10
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3081 if (depth11
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3082 result
= (GLchan
) luminance
;
3085 if (depth00
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3086 if (depth01
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3087 if (depth10
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3088 if (depth11
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3089 result
= (GLchan
) luminance
;
3092 if (depth00
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3093 if (depth01
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3094 if (depth10
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3095 if (depth11
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3096 result
= (GLchan
) luminance
;
3099 if (depth00
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3100 if (depth01
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3101 if (depth10
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3102 if (depth11
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3103 result
= (GLchan
) luminance
;
3106 if (depth00
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3107 if (depth01
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3108 if (depth10
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3109 if (depth11
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3110 result
= (GLchan
) luminance
;
3119 /* ordinary bilinear filtering */
3121 const GLfloat depthSample
3122 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3123 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
3127 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
3132 switch (tObj
->DepthMode
) {
3134 texel
[i
][RCOMP
] = result
;
3135 texel
[i
][GCOMP
] = result
;
3136 texel
[i
][BCOMP
] = result
;
3137 texel
[i
][ACOMP
] = CHAN_MAX
;
3140 texel
[i
][RCOMP
] = result
;
3141 texel
[i
][GCOMP
] = result
;
3142 texel
[i
][BCOMP
] = result
;
3143 texel
[i
][ACOMP
] = result
;
3146 texel
[i
][RCOMP
] = 0;
3147 texel
[i
][GCOMP
] = 0;
3148 texel
[i
][BCOMP
] = 0;
3149 texel
[i
][ACOMP
] = result
;
3152 _mesa_problem(ctx
, "Bad depth texture mode");
3161 * Experimental depth texture sampling function.
3164 sample_depth_texture2(const GLcontext
*ctx
,
3165 const struct gl_texture_unit
*texUnit
,
3166 GLuint n
, const GLfloat texcoords
[][4],
3169 const struct gl_texture_object
*texObj
= texUnit
->_Current
;
3170 const GLint baseLevel
= texObj
->BaseLevel
;
3171 const struct gl_texture_image
*texImage
= texObj
->Image
[0][baseLevel
];
3172 const GLuint width
= texImage
->Width
;
3173 const GLuint height
= texImage
->Height
;
3175 GLboolean lequal
, gequal
;
3177 if (texObj
->Target
!= GL_TEXTURE_2D
) {
3178 _mesa_problem(ctx
, "only 2-D depth textures supported at this time");
3182 if (texObj
->MinFilter
!= texObj
->MagFilter
) {
3183 _mesa_problem(ctx
, "mipmapped depth textures not supported at this time");
3187 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
3188 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
3189 * isn't a depth texture.
3191 if (texImage
->TexFormat
->BaseFormat
!= GL_DEPTH_COMPONENT
) {
3192 _mesa_problem(ctx
,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
3196 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
3198 if (texObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
3209 for (i
= 0; i
< n
; i
++) {
3211 GLint col
, row
, ii
, jj
, imin
, imax
, jmin
, jmax
, samples
, count
;
3214 col
= nearest_texel_location(texObj
->WrapS
, img
, width
,
3216 row
= nearest_texel_location(texObj
->WrapT
, img
, height
,
3224 if (imin
< 0) imin
= 0;
3225 if (imax
>= width
) imax
= width
- 1;
3226 if (jmin
< 0) jmin
= 0;
3227 if (jmax
>= height
) jmax
= height
- 1;
3229 samples
= (imax
- imin
+ 1) * (jmax
- jmin
+ 1);
3231 for (jj
= jmin
; jj
<= jmax
; jj
++) {
3232 for (ii
= imin
; ii
<= imax
; ii
++) {
3233 GLfloat depthSample
;
3234 texImage
->FetchTexelf(texImage
, ii
, jj
, 0, &depthSample
);
3235 if ((depthSample
<= r
[i
] && lequal
) ||
3236 (depthSample
>= r
[i
] && gequal
)) {
3242 w
= (GLfloat
) count
/ (GLfloat
) samples
;
3243 w
= CHAN_MAXF
- w
* (CHAN_MAXF
- (GLfloat
) ambient
);
3246 texel
[i
][RCOMP
] = lum
;
3247 texel
[i
][GCOMP
] = lum
;
3248 texel
[i
][BCOMP
] = lum
;
3249 texel
[i
][ACOMP
] = CHAN_MAX
;
3257 * We use this function when a texture object is in an "incomplete" state.
3258 * When a fragment program attempts to sample an incomplete texture we
3259 * return black (see issue 23 in GL_ARB_fragment_program spec).
3260 * Note: fragment programs don't observe the texture enable/disable flags.
3263 null_sample_func( GLcontext
*ctx
,
3264 const struct gl_texture_object
*tObj
, GLuint n
,
3265 const GLfloat texcoords
[][4], const GLfloat lambda
[],
3273 for (i
= 0; i
< n
; i
++) {
3277 rgba
[i
][ACOMP
] = CHAN_MAX
;
3283 * Choose the texture sampling function for the given texture object.
3286 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
3287 const struct gl_texture_object
*t
)
3289 if (!t
|| !t
->_Complete
) {
3290 return &null_sample_func
;
3293 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
3294 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->TexFormat
->BaseFormat
;
3296 switch (t
->Target
) {
3298 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3299 return &sample_depth_texture
;
3301 else if (needLambda
) {
3302 return &sample_lambda_1d
;
3304 else if (t
->MinFilter
== GL_LINEAR
) {
3305 return &sample_linear_1d
;
3308 ASSERT(t
->MinFilter
== GL_NEAREST
);
3309 return &sample_nearest_1d
;
3312 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3313 return &sample_depth_texture
;
3315 else if (needLambda
) {
3316 return &sample_lambda_2d
;
3318 else if (t
->MinFilter
== GL_LINEAR
) {
3319 return &sample_linear_2d
;
3322 /* check for a few optimized cases */
3323 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
3324 ASSERT(t
->MinFilter
== GL_NEAREST
);
3325 if (t
->WrapS
== GL_REPEAT
&&
3326 t
->WrapT
== GL_REPEAT
&&
3327 img
->_IsPowerOfTwo
&&
3329 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGB
) {
3330 return &opt_sample_rgb_2d
;
3332 else if (t
->WrapS
== GL_REPEAT
&&
3333 t
->WrapT
== GL_REPEAT
&&
3334 img
->_IsPowerOfTwo
&&
3336 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGBA
) {
3337 return &opt_sample_rgba_2d
;
3340 return &sample_nearest_2d
;
3345 return &sample_lambda_3d
;
3347 else if (t
->MinFilter
== GL_LINEAR
) {
3348 return &sample_linear_3d
;
3351 ASSERT(t
->MinFilter
== GL_NEAREST
);
3352 return &sample_nearest_3d
;
3354 case GL_TEXTURE_CUBE_MAP
:
3356 return &sample_lambda_cube
;
3358 else if (t
->MinFilter
== GL_LINEAR
) {
3359 return &sample_linear_cube
;
3362 ASSERT(t
->MinFilter
== GL_NEAREST
);
3363 return &sample_nearest_cube
;
3365 case GL_TEXTURE_RECTANGLE_NV
:
3366 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3367 return &sample_depth_texture
;
3369 else if (needLambda
) {
3370 return &sample_lambda_rect
;
3372 else if (t
->MinFilter
== GL_LINEAR
) {
3373 return &sample_linear_rect
;
3376 ASSERT(t
->MinFilter
== GL_NEAREST
);
3377 return &sample_nearest_rect
;
3379 case GL_TEXTURE_1D_ARRAY_EXT
:
3381 return &sample_lambda_1d_array
;
3383 else if (t
->MinFilter
== GL_LINEAR
) {
3384 return &sample_linear_1d_array
;
3387 ASSERT(t
->MinFilter
== GL_NEAREST
);
3388 return &sample_nearest_1d_array
;
3390 case GL_TEXTURE_2D_ARRAY_EXT
:
3392 return &sample_lambda_2d_array
;
3394 else if (t
->MinFilter
== GL_LINEAR
) {
3395 return &sample_linear_2d_array
;
3398 ASSERT(t
->MinFilter
== GL_NEAREST
);
3399 return &sample_nearest_2d_array
;
3403 "invalid target in _swrast_choose_texture_sample_func");
3404 return &null_sample_func
;