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");
2070 *weight
= FRAC(fcol
);
2075 sample_nearest_rect(GLcontext
*ctx
,
2076 const struct gl_texture_object
*tObj
, GLuint n
,
2077 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2080 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2081 const GLint width
= img
->Width
;
2082 const GLint height
= img
->Height
;
2088 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2089 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2090 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2091 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2092 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2093 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2094 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2096 for (i
= 0; i
< n
; i
++) {
2098 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2099 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2100 if (col
< 0 || col
>= width
|| row
< 0 || row
>= height
)
2101 COPY_CHAN4(rgba
[i
], tObj
->_BorderChan
);
2103 img
->FetchTexelc(img
, col
, row
, 0, rgba
[i
]);
2109 sample_linear_rect(GLcontext
*ctx
,
2110 const struct gl_texture_object
*tObj
, GLuint n
,
2111 const GLfloat texcoords
[][4],
2112 const GLfloat lambda
[], GLchan rgba
[][4])
2114 const struct gl_texture_image
*img
= tObj
->Image
[0][0];
2115 const GLint width
= img
->Width
;
2116 const GLint height
= img
->Height
;
2122 ASSERT(tObj
->WrapS
== GL_CLAMP
||
2123 tObj
->WrapS
== GL_CLAMP_TO_EDGE
||
2124 tObj
->WrapS
== GL_CLAMP_TO_BORDER
);
2125 ASSERT(tObj
->WrapT
== GL_CLAMP
||
2126 tObj
->WrapT
== GL_CLAMP_TO_EDGE
||
2127 tObj
->WrapT
== GL_CLAMP_TO_BORDER
);
2128 ASSERT(img
->TexFormat
->BaseFormat
!= GL_COLOR_INDEX
);
2130 for (i
= 0; i
< n
; i
++) {
2131 GLint i0
, j0
, i1
, j1
;
2132 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2134 GLbitfield useBorderColor
= 0x0;
2136 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0], width
,
2138 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1], height
,
2141 /* compute integer rows/columns */
2142 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2143 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2144 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2145 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2147 /* get four texel samples */
2148 if (useBorderColor
& (I0BIT
| J0BIT
))
2149 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2151 img
->FetchTexelc(img
, i0
, j0
, 0, t00
);
2153 if (useBorderColor
& (I1BIT
| J0BIT
))
2154 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2156 img
->FetchTexelc(img
, i1
, j0
, 0, t10
);
2158 if (useBorderColor
& (I0BIT
| J1BIT
))
2159 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2161 img
->FetchTexelc(img
, i0
, j1
, 0, t01
);
2163 if (useBorderColor
& (I1BIT
| J1BIT
))
2164 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2166 img
->FetchTexelc(img
, i1
, j1
, 0, t11
);
2168 lerp_rgba_2d(rgba
[i
], a
, b
, t00
, t10
, t01
, t11
);
2173 /** Sample Rect texture, using lambda to choose between min/magnification */
2175 sample_lambda_rect(GLcontext
*ctx
,
2176 const struct gl_texture_object
*tObj
, GLuint n
,
2177 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2180 GLuint minStart
, minEnd
, magStart
, magEnd
;
2182 /* We only need lambda to decide between minification and magnification.
2183 * There is no mipmapping with rectangular textures.
2185 compute_min_mag_ranges(tObj
, n
, lambda
,
2186 &minStart
, &minEnd
, &magStart
, &magEnd
);
2188 if (minStart
< minEnd
) {
2189 if (tObj
->MinFilter
== GL_NEAREST
) {
2190 sample_nearest_rect(ctx
, tObj
, minEnd
- minStart
,
2191 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2194 sample_linear_rect(ctx
, tObj
, minEnd
- minStart
,
2195 texcoords
+ minStart
, NULL
, rgba
+ minStart
);
2198 if (magStart
< magEnd
) {
2199 if (tObj
->MagFilter
== GL_NEAREST
) {
2200 sample_nearest_rect(ctx
, tObj
, magEnd
- magStart
,
2201 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2204 sample_linear_rect(ctx
, tObj
, magEnd
- magStart
,
2205 texcoords
+ magStart
, NULL
, rgba
+ magStart
);
2212 /**********************************************************************/
2213 /* 2D Texture Array Sampling Functions */
2214 /**********************************************************************/
2217 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2220 sample_2d_array_nearest(GLcontext
*ctx
,
2221 const struct gl_texture_object
*tObj
,
2222 const struct gl_texture_image
*img
,
2223 const GLfloat texcoord
[4],
2226 const GLint width
= img
->Width2
; /* without border, power of two */
2227 const GLint height
= img
->Height2
; /* without border, power of two */
2228 const GLint depth
= img
->Depth
;
2233 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2234 j
= nearest_texel_location(tObj
->WrapT
, img
, height
, texcoord
[1]);
2235 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2237 if (i
< 0 || i
>= (GLint
) img
->Width
||
2238 j
< 0 || j
>= (GLint
) img
->Height
||
2239 array
< 0 || array
>= (GLint
) img
->Depth
) {
2240 /* Need this test for GL_CLAMP_TO_BORDER mode */
2241 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2244 img
->FetchTexelc(img
, i
, j
, array
, rgba
);
2250 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2253 sample_2d_array_linear(GLcontext
*ctx
,
2254 const struct gl_texture_object
*tObj
,
2255 const struct gl_texture_image
*img
,
2256 const GLfloat texcoord
[4],
2259 const GLint width
= img
->Width2
;
2260 const GLint height
= img
->Height2
;
2261 const GLint depth
= img
->Depth
;
2262 GLint i0
, j0
, i1
, j1
;
2264 GLbitfield useBorderColor
= 0x0;
2266 GLchan t00
[4], t01
[4], t10
[4], t11
[4];
2268 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2269 linear_texel_locations(tObj
->WrapT
, img
, height
, texcoord
[1], &j0
, &j1
, &b
);
2270 array
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoord
[2], depth
);
2272 if (array
< 0 || array
>= depth
) {
2273 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2283 /* check if sampling texture border color */
2284 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2285 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2286 if (j0
< 0 || j0
>= height
) useBorderColor
|= J0BIT
;
2287 if (j1
< 0 || j1
>= height
) useBorderColor
|= J1BIT
;
2291 if (useBorderColor
& (I0BIT
| J0BIT
)) {
2292 COPY_CHAN4(t00
, tObj
->_BorderChan
);
2295 img
->FetchTexelc(img
, i0
, j0
, array
, t00
);
2297 if (useBorderColor
& (I1BIT
| J0BIT
)) {
2298 COPY_CHAN4(t10
, tObj
->_BorderChan
);
2301 img
->FetchTexelc(img
, i1
, j0
, array
, t10
);
2303 if (useBorderColor
& (I0BIT
| J1BIT
)) {
2304 COPY_CHAN4(t01
, tObj
->_BorderChan
);
2307 img
->FetchTexelc(img
, i0
, j1
, array
, t01
);
2309 if (useBorderColor
& (I1BIT
| J1BIT
)) {
2310 COPY_CHAN4(t11
, tObj
->_BorderChan
);
2313 img
->FetchTexelc(img
, i1
, j1
, array
, t11
);
2316 /* trilinear interpolation of samples */
2317 lerp_rgba_2d(rgba
, a
, b
, t00
, t10
, t01
, t11
);
2323 sample_2d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2324 const struct gl_texture_object
*tObj
,
2325 GLuint n
, const GLfloat texcoord
[][4],
2326 const GLfloat lambda
[], GLchan rgba
[][4])
2329 for (i
= 0; i
< n
; i
++) {
2330 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2331 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2338 sample_2d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2339 const struct gl_texture_object
*tObj
,
2340 GLuint n
, const GLfloat texcoord
[][4],
2341 const GLfloat lambda
[], GLchan rgba
[][4])
2344 ASSERT(lambda
!= NULL
);
2345 for (i
= 0; i
< n
; i
++) {
2346 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2347 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2348 texcoord
[i
], rgba
[i
]);
2354 sample_2d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2355 const struct gl_texture_object
*tObj
,
2356 GLuint n
, const GLfloat texcoord
[][4],
2357 const GLfloat lambda
[], GLchan rgba
[][4])
2360 ASSERT(lambda
!= NULL
);
2361 for (i
= 0; i
< n
; i
++) {
2362 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2363 if (level
>= tObj
->_MaxLevel
) {
2364 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2365 texcoord
[i
], rgba
[i
]);
2368 GLchan t0
[4], t1
[4]; /* texels */
2369 const GLfloat f
= FRAC(lambda
[i
]);
2370 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
],
2372 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1],
2374 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2381 sample_2d_array_linear_mipmap_linear(GLcontext
*ctx
,
2382 const struct gl_texture_object
*tObj
,
2383 GLuint n
, const GLfloat texcoord
[][4],
2384 const GLfloat lambda
[], GLchan rgba
[][4])
2387 ASSERT(lambda
!= NULL
);
2388 for (i
= 0; i
< n
; i
++) {
2389 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2390 if (level
>= tObj
->_MaxLevel
) {
2391 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2392 texcoord
[i
], rgba
[i
]);
2395 GLchan t0
[4], t1
[4]; /* texels */
2396 const GLfloat f
= FRAC(lambda
[i
]);
2397 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2399 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1],
2401 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2407 /** Sample 2D Array texture, nearest filtering for both min/magnification */
2409 sample_nearest_2d_array(GLcontext
*ctx
,
2410 const struct gl_texture_object
*tObj
, GLuint n
,
2411 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2415 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2417 for (i
= 0; i
< n
; i
++) {
2418 sample_2d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2424 /** Sample 2D Array texture, linear filtering for both min/magnification */
2426 sample_linear_2d_array(GLcontext
*ctx
,
2427 const struct gl_texture_object
*tObj
, GLuint n
,
2428 const GLfloat texcoords
[][4],
2429 const GLfloat lambda
[], GLchan rgba
[][4])
2432 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2434 for (i
= 0; i
< n
; i
++) {
2435 sample_2d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2440 /** Sample 2D Array texture, using lambda to choose between min/magnification */
2442 sample_lambda_2d_array(GLcontext
*ctx
,
2443 const struct gl_texture_object
*tObj
, GLuint n
,
2444 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2447 GLuint minStart
, minEnd
; /* texels with minification */
2448 GLuint magStart
, magEnd
; /* texels with magnification */
2451 ASSERT(lambda
!= NULL
);
2452 compute_min_mag_ranges(tObj
, n
, lambda
,
2453 &minStart
, &minEnd
, &magStart
, &magEnd
);
2455 if (minStart
< minEnd
) {
2456 /* do the minified texels */
2457 GLuint m
= minEnd
- minStart
;
2458 switch (tObj
->MinFilter
) {
2460 for (i
= minStart
; i
< minEnd
; i
++)
2461 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2462 texcoords
[i
], rgba
[i
]);
2465 for (i
= minStart
; i
< minEnd
; i
++)
2466 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2467 texcoords
[i
], rgba
[i
]);
2469 case GL_NEAREST_MIPMAP_NEAREST
:
2470 sample_2d_array_nearest_mipmap_nearest(ctx
, tObj
, m
,
2471 texcoords
+ minStart
,
2475 case GL_LINEAR_MIPMAP_NEAREST
:
2476 sample_2d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2477 texcoords
+ minStart
,
2481 case GL_NEAREST_MIPMAP_LINEAR
:
2482 sample_2d_array_nearest_mipmap_linear(ctx
, tObj
, m
,
2483 texcoords
+ minStart
,
2487 case GL_LINEAR_MIPMAP_LINEAR
:
2488 sample_2d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2489 texcoords
+ minStart
,
2494 _mesa_problem(ctx
, "Bad min filter in sample_2d_array_texture");
2499 if (magStart
< magEnd
) {
2500 /* do the magnified texels */
2501 switch (tObj
->MagFilter
) {
2503 for (i
= magStart
; i
< magEnd
; i
++)
2504 sample_2d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2505 texcoords
[i
], rgba
[i
]);
2508 for (i
= magStart
; i
< magEnd
; i
++)
2509 sample_2d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2510 texcoords
[i
], rgba
[i
]);
2513 _mesa_problem(ctx
, "Bad mag filter in sample_2d_array_texture");
2522 /**********************************************************************/
2523 /* 1D Texture Array Sampling Functions */
2524 /**********************************************************************/
2527 * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
2530 sample_1d_array_nearest(GLcontext
*ctx
,
2531 const struct gl_texture_object
*tObj
,
2532 const struct gl_texture_image
*img
,
2533 const GLfloat texcoord
[4],
2536 const GLint width
= img
->Width2
; /* without border, power of two */
2537 const GLint height
= img
->Height
;
2542 i
= nearest_texel_location(tObj
->WrapS
, img
, width
, texcoord
[0]);
2543 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2545 if (i
< 0 || i
>= (GLint
) img
->Width
||
2546 array
< 0 || array
>= (GLint
) img
->Height
) {
2547 /* Need this test for GL_CLAMP_TO_BORDER mode */
2548 COPY_CHAN4(rgba
, tObj
->_BorderChan
);
2551 img
->FetchTexelc(img
, i
, array
, 0, rgba
);
2557 * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
2560 sample_1d_array_linear(GLcontext
*ctx
,
2561 const struct gl_texture_object
*tObj
,
2562 const struct gl_texture_image
*img
,
2563 const GLfloat texcoord
[4],
2566 const GLint width
= img
->Width2
;
2567 const GLint height
= img
->Height
;
2570 GLbitfield useBorderColor
= 0x0;
2572 GLchan t0
[4], t1
[4];
2574 linear_texel_locations(tObj
->WrapS
, img
, width
, texcoord
[0], &i0
, &i1
, &a
);
2575 array
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoord
[1], height
);
2582 /* check if sampling texture border color */
2583 if (i0
< 0 || i0
>= width
) useBorderColor
|= I0BIT
;
2584 if (i1
< 0 || i1
>= width
) useBorderColor
|= I1BIT
;
2587 if (array
< 0 || array
>= height
) useBorderColor
|= K0BIT
;
2590 if (useBorderColor
& (I0BIT
| K0BIT
)) {
2591 COPY_CHAN4(t0
, tObj
->_BorderChan
);
2594 img
->FetchTexelc(img
, i0
, array
, 0, t0
);
2596 if (useBorderColor
& (I1BIT
| K0BIT
)) {
2597 COPY_CHAN4(t1
, tObj
->_BorderChan
);
2600 img
->FetchTexelc(img
, i1
, array
, 0, t1
);
2603 /* bilinear interpolation of samples */
2604 lerp_rgba(rgba
, a
, t0
, t1
);
2609 sample_1d_array_nearest_mipmap_nearest(GLcontext
*ctx
,
2610 const struct gl_texture_object
*tObj
,
2611 GLuint n
, const GLfloat texcoord
[][4],
2612 const GLfloat lambda
[], GLchan rgba
[][4])
2615 for (i
= 0; i
< n
; i
++) {
2616 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2617 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
],
2624 sample_1d_array_linear_mipmap_nearest(GLcontext
*ctx
,
2625 const struct gl_texture_object
*tObj
,
2626 GLuint n
, const GLfloat texcoord
[][4],
2627 const GLfloat lambda
[], GLchan rgba
[][4])
2630 ASSERT(lambda
!= NULL
);
2631 for (i
= 0; i
< n
; i
++) {
2632 GLint level
= nearest_mipmap_level(tObj
, lambda
[i
]);
2633 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
],
2634 texcoord
[i
], rgba
[i
]);
2640 sample_1d_array_nearest_mipmap_linear(GLcontext
*ctx
,
2641 const struct gl_texture_object
*tObj
,
2642 GLuint n
, const GLfloat texcoord
[][4],
2643 const GLfloat lambda
[], GLchan rgba
[][4])
2646 ASSERT(lambda
!= NULL
);
2647 for (i
= 0; i
< n
; i
++) {
2648 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2649 if (level
>= tObj
->_MaxLevel
) {
2650 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2651 texcoord
[i
], rgba
[i
]);
2654 GLchan t0
[4], t1
[4]; /* texels */
2655 const GLfloat f
= FRAC(lambda
[i
]);
2656 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2657 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2658 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2665 sample_1d_array_linear_mipmap_linear(GLcontext
*ctx
,
2666 const struct gl_texture_object
*tObj
,
2667 GLuint n
, const GLfloat texcoord
[][4],
2668 const GLfloat lambda
[], GLchan rgba
[][4])
2671 ASSERT(lambda
!= NULL
);
2672 for (i
= 0; i
< n
; i
++) {
2673 GLint level
= linear_mipmap_level(tObj
, lambda
[i
]);
2674 if (level
>= tObj
->_MaxLevel
) {
2675 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->_MaxLevel
],
2676 texcoord
[i
], rgba
[i
]);
2679 GLchan t0
[4], t1
[4]; /* texels */
2680 const GLfloat f
= FRAC(lambda
[i
]);
2681 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
], texcoord
[i
], t0
);
2682 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][level
+1], texcoord
[i
], t1
);
2683 lerp_rgba(rgba
[i
], f
, t0
, t1
);
2689 /** Sample 1D Array texture, nearest filtering for both min/magnification */
2691 sample_nearest_1d_array(GLcontext
*ctx
,
2692 const struct gl_texture_object
*tObj
, GLuint n
,
2693 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2697 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2699 for (i
= 0; i
< n
; i
++) {
2700 sample_1d_array_nearest(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2705 /** Sample 1D Array texture, linear filtering for both min/magnification */
2707 sample_linear_1d_array(GLcontext
*ctx
,
2708 const struct gl_texture_object
*tObj
, GLuint n
,
2709 const GLfloat texcoords
[][4],
2710 const GLfloat lambda
[], GLchan rgba
[][4])
2713 struct gl_texture_image
*image
= tObj
->Image
[0][tObj
->BaseLevel
];
2715 for (i
= 0; i
< n
; i
++) {
2716 sample_1d_array_linear(ctx
, tObj
, image
, texcoords
[i
], rgba
[i
]);
2721 /** Sample 1D Array texture, using lambda to choose between min/magnification */
2723 sample_lambda_1d_array(GLcontext
*ctx
,
2724 const struct gl_texture_object
*tObj
, GLuint n
,
2725 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2728 GLuint minStart
, minEnd
; /* texels with minification */
2729 GLuint magStart
, magEnd
; /* texels with magnification */
2732 ASSERT(lambda
!= NULL
);
2733 compute_min_mag_ranges(tObj
, n
, lambda
,
2734 &minStart
, &minEnd
, &magStart
, &magEnd
);
2736 if (minStart
< minEnd
) {
2737 /* do the minified texels */
2738 GLuint m
= minEnd
- minStart
;
2739 switch (tObj
->MinFilter
) {
2741 for (i
= minStart
; i
< minEnd
; i
++)
2742 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2743 texcoords
[i
], rgba
[i
]);
2746 for (i
= minStart
; i
< minEnd
; i
++)
2747 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2748 texcoords
[i
], rgba
[i
]);
2750 case GL_NEAREST_MIPMAP_NEAREST
:
2751 sample_1d_array_nearest_mipmap_nearest(ctx
, tObj
, m
, texcoords
+ minStart
,
2752 lambda
+ minStart
, rgba
+ minStart
);
2754 case GL_LINEAR_MIPMAP_NEAREST
:
2755 sample_1d_array_linear_mipmap_nearest(ctx
, tObj
, m
,
2756 texcoords
+ minStart
,
2760 case GL_NEAREST_MIPMAP_LINEAR
:
2761 sample_1d_array_nearest_mipmap_linear(ctx
, tObj
, m
, texcoords
+ minStart
,
2762 lambda
+ minStart
, rgba
+ minStart
);
2764 case GL_LINEAR_MIPMAP_LINEAR
:
2765 sample_1d_array_linear_mipmap_linear(ctx
, tObj
, m
,
2766 texcoords
+ minStart
,
2771 _mesa_problem(ctx
, "Bad min filter in sample_1d_array_texture");
2776 if (magStart
< magEnd
) {
2777 /* do the magnified texels */
2778 switch (tObj
->MagFilter
) {
2780 for (i
= magStart
; i
< magEnd
; i
++)
2781 sample_1d_array_nearest(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2782 texcoords
[i
], rgba
[i
]);
2785 for (i
= magStart
; i
< magEnd
; i
++)
2786 sample_1d_array_linear(ctx
, tObj
, tObj
->Image
[0][tObj
->BaseLevel
],
2787 texcoords
[i
], rgba
[i
]);
2790 _mesa_problem(ctx
, "Bad mag filter in sample_1d_array_texture");
2798 * Sample a shadow/depth texture.
2801 sample_depth_texture( GLcontext
*ctx
,
2802 const struct gl_texture_object
*tObj
, GLuint n
,
2803 const GLfloat texcoords
[][4], const GLfloat lambda
[],
2806 const GLint baseLevel
= tObj
->BaseLevel
;
2807 const struct gl_texture_image
*img
= tObj
->Image
[0][baseLevel
];
2808 const GLint width
= img
->Width
;
2809 const GLint height
= img
->Height
;
2810 const GLint depth
= img
->Depth
;
2811 const GLuint compare_coord
= (tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
)
2819 ASSERT(img
->TexFormat
->BaseFormat
== GL_DEPTH_COMPONENT
||
2820 img
->TexFormat
->BaseFormat
== GL_DEPTH_STENCIL_EXT
);
2822 ASSERT(tObj
->Target
== GL_TEXTURE_1D
||
2823 tObj
->Target
== GL_TEXTURE_2D
||
2824 tObj
->Target
== GL_TEXTURE_RECTANGLE_NV
||
2825 tObj
->Target
== GL_TEXTURE_1D_ARRAY_EXT
||
2826 tObj
->Target
== GL_TEXTURE_2D_ARRAY_EXT
);
2828 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
2830 /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
2832 function
= tObj
->_Function
;
2833 if (tObj
->MagFilter
== GL_NEAREST
) {
2835 for (i
= 0; i
< n
; i
++) {
2836 GLfloat depthSample
;
2837 GLint col
, row
, slice
;
2839 switch (tObj
->Target
) {
2840 case GL_TEXTURE_RECTANGLE_ARB
:
2841 col
= clamp_rect_coord_nearest(tObj
->WrapS
, texcoords
[i
][0], width
);
2842 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2847 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2854 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2856 row
= nearest_texel_location(tObj
->WrapT
, img
, height
,
2861 case GL_TEXTURE_1D_ARRAY_EXT
:
2862 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2864 row
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2868 case GL_TEXTURE_2D_ARRAY_EXT
:
2869 col
= nearest_texel_location(tObj
->WrapS
, img
, width
,
2871 row
= nearest_texel_location(tObj
->WrapT
, img
, height
,
2873 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2877 if (col
>= 0 && row
>= 0 && col
< width
&& row
< height
&&
2878 slice
>= 0 && slice
< depth
) {
2879 img
->FetchTexelf(img
, col
, row
, slice
, &depthSample
);
2882 depthSample
= tObj
->BorderColor
[0];
2887 result
= (texcoords
[i
][compare_coord
] <= depthSample
) ? CHAN_MAX
: ambient
;
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
;
2911 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
2914 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
2918 switch (tObj
->DepthMode
) {
2920 texel
[i
][RCOMP
] = result
;
2921 texel
[i
][GCOMP
] = result
;
2922 texel
[i
][BCOMP
] = result
;
2923 texel
[i
][ACOMP
] = CHAN_MAX
;
2926 texel
[i
][RCOMP
] = result
;
2927 texel
[i
][GCOMP
] = result
;
2928 texel
[i
][BCOMP
] = result
;
2929 texel
[i
][ACOMP
] = result
;
2932 texel
[i
][RCOMP
] = 0;
2933 texel
[i
][GCOMP
] = 0;
2934 texel
[i
][BCOMP
] = 0;
2935 texel
[i
][ACOMP
] = result
;
2938 _mesa_problem(ctx
, "Bad depth texture mode");
2944 ASSERT(tObj
->MagFilter
== GL_LINEAR
);
2945 for (i
= 0; i
< n
; i
++) {
2946 GLfloat depth00
, depth01
, depth10
, depth11
;
2947 GLint i0
, i1
, j0
, j1
;
2950 GLuint useBorderTexel
;
2952 switch (tObj
->Target
) {
2953 case GL_TEXTURE_RECTANGLE_ARB
:
2954 clamp_rect_coord_linear(tObj
->WrapS
, texcoords
[i
][0],
2955 width
, &i0
, &i1
, &a
);
2956 clamp_rect_coord_linear(tObj
->WrapT
, texcoords
[i
][1],
2957 height
, &j0
, &j1
, &b
);
2963 linear_texel_locations(tObj
->WrapS
, img
, width
,
2964 texcoords
[i
][0], &i0
, &i1
, &a
);
2965 linear_texel_locations(tObj
->WrapT
, img
, height
,
2966 texcoords
[i
][1], &j0
, &j1
, &b
);
2970 case GL_TEXTURE_1D_ARRAY_EXT
:
2971 linear_texel_locations(tObj
->WrapS
, img
, width
,
2972 texcoords
[i
][0], &i0
, &i1
, &a
);
2973 j0
= clamp_rect_coord_nearest(tObj
->WrapT
, texcoords
[i
][1], height
);
2978 case GL_TEXTURE_2D_ARRAY_EXT
:
2979 linear_texel_locations(tObj
->WrapS
, img
, width
,
2980 texcoords
[i
][0], &i0
, &i1
, &a
);
2981 linear_texel_locations(tObj
->WrapT
, img
, height
,
2982 texcoords
[i
][1], &j0
, &j1
, &b
);
2983 slice
= clamp_rect_coord_nearest(tObj
->WrapR
, texcoords
[i
][2], depth
);
2991 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
2997 if (i0
< 0 || i0
>= (GLint
) width
) useBorderTexel
|= I0BIT
;
2998 if (i1
< 0 || i1
>= (GLint
) width
) useBorderTexel
|= I1BIT
;
2999 if (j0
< 0 || j0
>= (GLint
) height
) useBorderTexel
|= J0BIT
;
3000 if (j1
< 0 || j1
>= (GLint
) height
) useBorderTexel
|= J1BIT
;
3003 if (slice
< 0 || slice
>= (GLint
) depth
) {
3004 depth00
= tObj
->BorderColor
[0];
3005 depth01
= tObj
->BorderColor
[0];
3006 depth10
= tObj
->BorderColor
[0];
3007 depth11
= tObj
->BorderColor
[0];
3010 /* get four depth samples from the texture */
3011 if (useBorderTexel
& (I0BIT
| J0BIT
)) {
3012 depth00
= tObj
->BorderColor
[0];
3015 img
->FetchTexelf(img
, i0
, j0
, slice
, &depth00
);
3017 if (useBorderTexel
& (I1BIT
| J0BIT
)) {
3018 depth10
= tObj
->BorderColor
[0];
3021 img
->FetchTexelf(img
, i1
, j0
, slice
, &depth10
);
3024 if (tObj
->Target
!= GL_TEXTURE_1D_ARRAY_EXT
) {
3025 if (useBorderTexel
& (I0BIT
| J1BIT
)) {
3026 depth01
= tObj
->BorderColor
[0];
3029 img
->FetchTexelf(img
, i0
, j1
, slice
, &depth01
);
3031 if (useBorderTexel
& (I1BIT
| J1BIT
)) {
3032 depth11
= tObj
->BorderColor
[0];
3035 img
->FetchTexelf(img
, i1
, j1
, slice
, &depth11
);
3045 /* compute a single weighted depth sample and do one comparison */
3046 const GLfloat depthSample
3047 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3048 if ((depthSample
<= texcoords
[i
][compare_coord
] && function
== GL_LEQUAL
) ||
3049 (depthSample
>= texcoords
[i
][compare_coord
] && function
== GL_GEQUAL
)) {
3057 /* Do four depth/R comparisons and compute a weighted result.
3058 * If this touches on somebody's I.P., I'll remove this code
3061 const GLfloat d
= (CHAN_MAXF
- (GLfloat
) ambient
) * 0.25F
;
3062 GLfloat luminance
= CHAN_MAXF
;
3066 if (depth00
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3067 if (depth01
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3068 if (depth10
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3069 if (depth11
<= texcoords
[i
][compare_coord
]) luminance
-= d
;
3070 result
= (GLchan
) luminance
;
3073 if (depth00
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3074 if (depth01
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3075 if (depth10
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3076 if (depth11
>= texcoords
[i
][compare_coord
]) luminance
-= d
;
3077 result
= (GLchan
) luminance
;
3080 if (depth00
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3081 if (depth01
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3082 if (depth10
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3083 if (depth11
< texcoords
[i
][compare_coord
]) luminance
-= d
;
3084 result
= (GLchan
) luminance
;
3087 if (depth00
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3088 if (depth01
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3089 if (depth10
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3090 if (depth11
> texcoords
[i
][compare_coord
]) luminance
-= d
;
3091 result
= (GLchan
) luminance
;
3094 if (depth00
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3095 if (depth01
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3096 if (depth10
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3097 if (depth11
== texcoords
[i
][compare_coord
]) luminance
-= d
;
3098 result
= (GLchan
) luminance
;
3101 if (depth00
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3102 if (depth01
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3103 if (depth10
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3104 if (depth11
!= texcoords
[i
][compare_coord
]) luminance
-= d
;
3105 result
= (GLchan
) luminance
;
3114 /* ordinary bilinear filtering */
3116 const GLfloat depthSample
3117 = lerp_2d(a
, b
, depth00
, depth10
, depth01
, depth11
);
3118 CLAMPED_FLOAT_TO_CHAN(result
, depthSample
);
3122 _mesa_problem(ctx
, "Bad compare func in sample_depth_texture");
3127 switch (tObj
->DepthMode
) {
3129 texel
[i
][RCOMP
] = result
;
3130 texel
[i
][GCOMP
] = result
;
3131 texel
[i
][BCOMP
] = result
;
3132 texel
[i
][ACOMP
] = CHAN_MAX
;
3135 texel
[i
][RCOMP
] = result
;
3136 texel
[i
][GCOMP
] = result
;
3137 texel
[i
][BCOMP
] = result
;
3138 texel
[i
][ACOMP
] = result
;
3141 texel
[i
][RCOMP
] = 0;
3142 texel
[i
][GCOMP
] = 0;
3143 texel
[i
][BCOMP
] = 0;
3144 texel
[i
][ACOMP
] = result
;
3147 _mesa_problem(ctx
, "Bad depth texture mode");
3156 * Experimental depth texture sampling function.
3159 sample_depth_texture2(const GLcontext
*ctx
,
3160 const struct gl_texture_unit
*texUnit
,
3161 GLuint n
, const GLfloat texcoords
[][4],
3164 const struct gl_texture_object
*texObj
= texUnit
->_Current
;
3165 const GLint baseLevel
= texObj
->BaseLevel
;
3166 const struct gl_texture_image
*texImage
= texObj
->Image
[0][baseLevel
];
3167 const GLuint width
= texImage
->Width
;
3168 const GLuint height
= texImage
->Height
;
3170 GLboolean lequal
, gequal
;
3172 if (texObj
->Target
!= GL_TEXTURE_2D
) {
3173 _mesa_problem(ctx
, "only 2-D depth textures supported at this time");
3177 if (texObj
->MinFilter
!= texObj
->MagFilter
) {
3178 _mesa_problem(ctx
, "mipmapped depth textures not supported at this time");
3182 /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
3183 * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
3184 * isn't a depth texture.
3186 if (texImage
->TexFormat
->BaseFormat
!= GL_DEPTH_COMPONENT
) {
3187 _mesa_problem(ctx
,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
3191 UNCLAMPED_FLOAT_TO_CHAN(ambient
, tObj
->ShadowAmbient
);
3193 if (texObj
->CompareOperator
== GL_TEXTURE_LEQUAL_R_SGIX
) {
3204 for (i
= 0; i
< n
; i
++) {
3206 GLint col
, row
, ii
, jj
, imin
, imax
, jmin
, jmax
, samples
, count
;
3209 col
= nearest_texel_location(texObj
->WrapS
, img
, width
,
3211 row
= nearest_texel_location(texObj
->WrapT
, img
, height
,
3219 if (imin
< 0) imin
= 0;
3220 if (imax
>= width
) imax
= width
- 1;
3221 if (jmin
< 0) jmin
= 0;
3222 if (jmax
>= height
) jmax
= height
- 1;
3224 samples
= (imax
- imin
+ 1) * (jmax
- jmin
+ 1);
3226 for (jj
= jmin
; jj
<= jmax
; jj
++) {
3227 for (ii
= imin
; ii
<= imax
; ii
++) {
3228 GLfloat depthSample
;
3229 texImage
->FetchTexelf(texImage
, ii
, jj
, 0, &depthSample
);
3230 if ((depthSample
<= r
[i
] && lequal
) ||
3231 (depthSample
>= r
[i
] && gequal
)) {
3237 w
= (GLfloat
) count
/ (GLfloat
) samples
;
3238 w
= CHAN_MAXF
- w
* (CHAN_MAXF
- (GLfloat
) ambient
);
3241 texel
[i
][RCOMP
] = lum
;
3242 texel
[i
][GCOMP
] = lum
;
3243 texel
[i
][BCOMP
] = lum
;
3244 texel
[i
][ACOMP
] = CHAN_MAX
;
3252 * We use this function when a texture object is in an "incomplete" state.
3253 * When a fragment program attempts to sample an incomplete texture we
3254 * return black (see issue 23 in GL_ARB_fragment_program spec).
3255 * Note: fragment programs don't observe the texture enable/disable flags.
3258 null_sample_func( GLcontext
*ctx
,
3259 const struct gl_texture_object
*tObj
, GLuint n
,
3260 const GLfloat texcoords
[][4], const GLfloat lambda
[],
3268 for (i
= 0; i
< n
; i
++) {
3272 rgba
[i
][ACOMP
] = CHAN_MAX
;
3278 * Choose the texture sampling function for the given texture object.
3281 _swrast_choose_texture_sample_func( GLcontext
*ctx
,
3282 const struct gl_texture_object
*t
)
3284 if (!t
|| !t
->_Complete
) {
3285 return &null_sample_func
;
3288 const GLboolean needLambda
= (GLboolean
) (t
->MinFilter
!= t
->MagFilter
);
3289 const GLenum format
= t
->Image
[0][t
->BaseLevel
]->TexFormat
->BaseFormat
;
3291 switch (t
->Target
) {
3293 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3294 return &sample_depth_texture
;
3296 else if (needLambda
) {
3297 return &sample_lambda_1d
;
3299 else if (t
->MinFilter
== GL_LINEAR
) {
3300 return &sample_linear_1d
;
3303 ASSERT(t
->MinFilter
== GL_NEAREST
);
3304 return &sample_nearest_1d
;
3307 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3308 return &sample_depth_texture
;
3310 else if (needLambda
) {
3311 return &sample_lambda_2d
;
3313 else if (t
->MinFilter
== GL_LINEAR
) {
3314 return &sample_linear_2d
;
3317 /* check for a few optimized cases */
3318 const struct gl_texture_image
*img
= t
->Image
[0][t
->BaseLevel
];
3319 ASSERT(t
->MinFilter
== GL_NEAREST
);
3320 if (t
->WrapS
== GL_REPEAT
&&
3321 t
->WrapT
== GL_REPEAT
&&
3322 img
->_IsPowerOfTwo
&&
3324 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGB
) {
3325 return &opt_sample_rgb_2d
;
3327 else if (t
->WrapS
== GL_REPEAT
&&
3328 t
->WrapT
== GL_REPEAT
&&
3329 img
->_IsPowerOfTwo
&&
3331 img
->TexFormat
->MesaFormat
== MESA_FORMAT_RGBA
) {
3332 return &opt_sample_rgba_2d
;
3335 return &sample_nearest_2d
;
3340 return &sample_lambda_3d
;
3342 else if (t
->MinFilter
== GL_LINEAR
) {
3343 return &sample_linear_3d
;
3346 ASSERT(t
->MinFilter
== GL_NEAREST
);
3347 return &sample_nearest_3d
;
3349 case GL_TEXTURE_CUBE_MAP
:
3351 return &sample_lambda_cube
;
3353 else if (t
->MinFilter
== GL_LINEAR
) {
3354 return &sample_linear_cube
;
3357 ASSERT(t
->MinFilter
== GL_NEAREST
);
3358 return &sample_nearest_cube
;
3360 case GL_TEXTURE_RECTANGLE_NV
:
3361 if (format
== GL_DEPTH_COMPONENT
|| format
== GL_DEPTH_STENCIL_EXT
) {
3362 return &sample_depth_texture
;
3364 else if (needLambda
) {
3365 return &sample_lambda_rect
;
3367 else if (t
->MinFilter
== GL_LINEAR
) {
3368 return &sample_linear_rect
;
3371 ASSERT(t
->MinFilter
== GL_NEAREST
);
3372 return &sample_nearest_rect
;
3374 case GL_TEXTURE_1D_ARRAY_EXT
:
3376 return &sample_lambda_1d_array
;
3378 else if (t
->MinFilter
== GL_LINEAR
) {
3379 return &sample_linear_1d_array
;
3382 ASSERT(t
->MinFilter
== GL_NEAREST
);
3383 return &sample_nearest_1d_array
;
3385 case GL_TEXTURE_2D_ARRAY_EXT
:
3387 return &sample_lambda_2d_array
;
3389 else if (t
->MinFilter
== GL_LINEAR
) {
3390 return &sample_linear_2d_array
;
3393 ASSERT(t
->MinFilter
== GL_NEAREST
);
3394 return &sample_nearest_2d_array
;
3398 "invalid target in _swrast_choose_texture_sample_func");
3399 return &null_sample_func
;