diff options
Diffstat (limited to 'src/mesa/swrast/s_texture.c')
-rw-r--r-- | src/mesa/swrast/s_texture.c | 2539 |
1 files changed, 2539 insertions, 0 deletions
diff --git a/src/mesa/swrast/s_texture.c b/src/mesa/swrast/s_texture.c new file mode 100644 index 00000000000..04f8645b97f --- /dev/null +++ b/src/mesa/swrast/s_texture.c @@ -0,0 +1,2539 @@ +/* $Id: s_texture.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include "glheader.h" +#include "context.h" +#include "colormac.h" +#include "macros.h" +#include "mmath.h" +#include "mem.h" +#include "teximage.h" + +#include "s_pb.h" +#include "s_texture.h" + + + + +/* + * Paletted texture sampling. + * Input: tObj - the texture object + * index - the palette index (8-bit only) + * Output: red, green, blue, alpha - the texel color + */ +static void palette_sample(const struct gl_texture_object *tObj, + GLint index, GLchan rgba[4] ) +{ + GLcontext *ctx = _mesa_get_current_context(); /* THIS IS A HACK */ + const GLchan *palette; + GLenum format; + + if (ctx->Texture.SharedPalette) { + ASSERT(!ctx->Texture.Palette.FloatTable); + palette = (const GLchan *) ctx->Texture.Palette.Table; + format = ctx->Texture.Palette.Format; + } + else { + ASSERT(!tObj->Palette.FloatTable); + palette = (const GLchan *) tObj->Palette.Table; + format = tObj->Palette.Format; + } + + switch (format) { + case GL_ALPHA: + rgba[ACOMP] = palette[index]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = palette[index]; + return; + case GL_LUMINANCE_ALPHA: + rgba[RCOMP] = palette[(index << 1) + 0]; + rgba[ACOMP] = palette[(index << 1) + 1]; + return; + case GL_RGB: + rgba[RCOMP] = palette[index * 3 + 0]; + rgba[GCOMP] = palette[index * 3 + 1]; + rgba[BCOMP] = palette[index * 3 + 2]; + return; + case GL_RGBA: + rgba[RCOMP] = palette[(index << 2) + 0]; + rgba[GCOMP] = palette[(index << 2) + 1]; + rgba[BCOMP] = palette[(index << 2) + 2]; + rgba[ACOMP] = palette[(index << 2) + 3]; + return; + default: + gl_problem(NULL, "Bad palette format in palette_sample"); + } +} + + + +/* + * These values are used in the fixed-point arithmetic used + * for linear filtering. + */ +#define WEIGHT_SCALE 65536.0F +#define WEIGHT_SHIFT 16 + + +/* + * Used to compute texel locations for linear sampling. + */ +#define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \ +{ \ + if (wrapMode == GL_REPEAT) { \ + U = S * SIZE - 0.5F; \ + I0 = ((GLint) myFloor(U)) & (SIZE - 1); \ + I1 = (I0 + 1) & (SIZE - 1); \ + } \ + else { \ + U = S * SIZE; \ + if (U < 0.0F) \ + U = 0.0F; \ + else if (U >= SIZE) \ + U = SIZE; \ + U -= 0.5F; \ + I0 = (GLint) myFloor(U); \ + I1 = I0 + 1; \ + if (wrapMode == GL_CLAMP_TO_EDGE) { \ + if (I0 < 0) \ + I0 = 0; \ + if (I1 >= SIZE) \ + I1 = SIZE - 1; \ + } \ + } \ +} + + +/* + * Used to compute texel location for nearest sampling. + */ +#define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \ +{ \ + if (wrapMode == GL_REPEAT) { \ + /* s limited to [0,1) */ \ + /* i limited to [0,width-1] */ \ + I = (GLint) (S * SIZE); \ + if (S < 0.0F) \ + I -= 1; \ + I &= (SIZE - 1); \ + } \ + else if (wrapMode == GL_CLAMP_TO_EDGE) { \ + const GLfloat min = 1.0F / (2.0F * SIZE); \ + const GLfloat max = 1.0F - min; \ + if (S < min) \ + I = 0; \ + else if (S > max) \ + I = SIZE - 1; \ + else \ + I = (GLint) (S * SIZE); \ + } \ + else { \ + ASSERT(wrapMode == GL_CLAMP); \ + /* s limited to [0,1] */ \ + /* i limited to [0,width-1] */ \ + if (S <= 0.0F) \ + I = 0; \ + else if (S >= 1.0F) \ + I = SIZE - 1; \ + else \ + I = (GLint) (S * SIZE); \ + } \ +} + + +/* + * Compute linear mipmap levels for given lambda. + */ +#define COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level) \ +{ \ + if (lambda < 0.0F) \ + lambda = 0.0F; \ + else if (lambda > tObj->M) \ + lambda = tObj->M; \ + level = (GLint) (tObj->BaseLevel + lambda); \ +} + + +/* + * Compute nearest mipmap level for given lambda. + */ +#define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \ +{ \ + if (lambda <= 0.5F) \ + lambda = 0.0F; \ + else if (lambda > tObj->M + 0.4999F) \ + lambda = tObj->M + 0.4999F; \ + level = (GLint) (tObj->BaseLevel + lambda + 0.5F); \ + if (level > tObj->P) \ + level = tObj->P; \ +} + + + + +/* + * Bitflags for texture border color sampling. + */ +#define I0BIT 1 +#define I1BIT 2 +#define J0BIT 4 +#define J1BIT 8 +#define K0BIT 16 +#define K1BIT 32 + + + +/**********************************************************************/ +/* 1-D Texture Sampling Functions */ +/**********************************************************************/ + + +/* + * Return floor of x, being careful of negative values. + */ +static GLfloat myFloor(GLfloat x) +{ + if (x < 0.0F) + return (GLfloat) ((GLint) x - 1); + else + return (GLfloat) (GLint) x; +} + + +/* + * Return the fractional part of x. + */ +#define myFrac(x) ( (x) - myFloor(x) ) + + + + +/* + * Given 1-D texture image and an (i) texel column coordinate, return the + * texel color. + */ +static void get_1d_texel( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, GLint i, + GLchan rgba[4] ) +{ + const GLchan *texel; + +#ifdef DEBUG + GLint width = img->Width; + assert(i >= 0); + assert(i < width); +#endif + + switch (img->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[i]; + palette_sample(tObj, index, rgba); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[ i ]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[ i ]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + i * 2; + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + i * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + i * 4; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in get_1d_texel"); + return; + } +} + + + +/* + * Return the texture sample for coordinate (s) using GL_NEAREST filter. + */ +static void sample_1d_nearest( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, GLchan rgba[4] ) +{ + const GLint width = img->Width2; /* without border, power of two */ + const GLchan *texel; + GLint i; + + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i); + + /* skip over the border, if any */ + i += img->Border; + + /* Get the texel */ + switch (img->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[i]; + palette_sample(tObj, index, rgba ); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[i]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[i]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + i * 2; + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + i * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + i * 4; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in sample_1d_nearest"); + } +} + + + +/* + * Return the texture sample for coordinate (s) using GL_LINEAR filter. + */ +static void sample_1d_linear( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, + GLchan rgba[4] ) +{ + const GLint width = img->Width2; + GLint i0, i1; + GLfloat u; + GLuint useBorderColor; + + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1); + + useBorderColor = 0; + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + } + + { + const GLfloat a = myFrac(u); + /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */ + const GLint w0 = (GLint) ((1.0F-a) * WEIGHT_SCALE + 0.5F); + const GLint w1 = (GLint) ( a * WEIGHT_SCALE + 0.5F); + + GLchan t0[4], t1[4]; /* texels */ + + if (useBorderColor & I0BIT) { + COPY_CHAN4(t0, tObj->BorderColor); + } + else { + get_1d_texel( tObj, img, i0, t0 ); + } + if (useBorderColor & I1BIT) { + COPY_CHAN4(t1, tObj->BorderColor); + } + else { + get_1d_texel( tObj, img, i1, t1 ); + } + + rgba[0] = (GLchan) ((w0 * t0[0] + w1 * t1[0]) >> WEIGHT_SHIFT); + rgba[1] = (GLchan) ((w0 * t0[1] + w1 * t1[1]) >> WEIGHT_SHIFT); + rgba[2] = (GLchan) ((w0 * t0[2] + w1 * t1[2]) >> WEIGHT_SHIFT); + rgba[3] = (GLchan) ((w0 * t0[3] + w1 * t1[3]) >> WEIGHT_SHIFT); + } +} + + +static void +sample_1d_nearest_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_1d_nearest( tObj, tObj->Image[level], s, rgba ); +} + + +static void +sample_1d_linear_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_1d_linear( tObj, tObj->Image[level], s, rgba ); +} + + + +static void +sample_1d_nearest_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_1d_nearest( tObj, tObj->Image[tObj->P], s, rgba ); + } + else { + GLchan t0[4], t1[4]; + const GLfloat f = myFrac(lambda); + sample_1d_nearest( tObj, tObj->Image[level ], s, t0 ); + sample_1d_nearest( tObj, tObj->Image[level+1], s, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + + +static void +sample_1d_linear_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_1d_linear( tObj, tObj->Image[tObj->P], s, rgba ); + } + else { + GLchan t0[4], t1[4]; + const GLfloat f = myFrac(lambda); + sample_1d_linear( tObj, tObj->Image[level ], s, t0 ); + sample_1d_linear( tObj, tObj->Image[level+1], s, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + + +static void sample_nearest_1d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) t; + (void) u; + (void) lambda; + for (i=0;i<n;i++) { + sample_1d_nearest( tObj, image, s[i], rgba[i] ); + } +} + + + +static void sample_linear_1d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) t; + (void) u; + (void) lambda; + for (i=0;i<n;i++) { + sample_1d_linear( tObj, image, s[i], rgba[i] ); + } +} + + +/* + * Given an (s) texture coordinate and lambda (level of detail) value, + * return a texture sample. + * + */ +static void sample_lambda_1d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + + (void) t; + (void) u; + + for (i=0;i<n;i++) { + if (lambda[i] > tObj->MinMagThresh) { + /* minification */ + switch (tObj->MinFilter) { + case GL_NEAREST: + sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] ); + break; + case GL_LINEAR: + sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_1d_nearest_mipmap_nearest( tObj, lambda[i], s[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_1d_linear_mipmap_nearest( tObj, s[i], lambda[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_1d_nearest_mipmap_linear( tObj, s[i], lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_1d_linear_mipmap_linear( tObj, s[i], lambda[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad min filter in sample_1d_texture"); + return; + } + } + else { + /* magnification */ + switch (tObj->MagFilter) { + case GL_NEAREST: + sample_1d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] ); + break; + case GL_LINEAR: + sample_1d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad mag filter in sample_1d_texture"); + return; + } + } + } +} + + + + +/**********************************************************************/ +/* 2-D Texture Sampling Functions */ +/**********************************************************************/ + + +/* + * Given a texture image and an (i,j) integer texel coordinate, return the + * texel color. + */ +static void get_2d_texel( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, GLint i, GLint j, + GLchan rgba[4] ) +{ + const GLint width = img->Width; /* includes border */ + const GLchan *texel; + +#ifdef DEBUG + const GLint height = img->Height; /* includes border */ + assert(i >= 0); + assert(i < width); + assert(j >= 0); + assert(j < height); +#endif + + switch (img->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[ width *j + i ]; + palette_sample(tObj, index, rgba ); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[ width * j + i ]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[ width * j + i ]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + (width * j + i) * 2; + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + (width * j + i) * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + (width * j + i) * 4; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in get_2d_texel"); + } +} + + + +/* + * Return the texture sample for coordinate (s,t) using GL_NEAREST filter. + */ +static void sample_2d_nearest( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, GLfloat t, + GLchan rgba[] ) +{ + const GLint imgWidth = img->Width; /* includes border */ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLchan *texel; + GLint i, j; + + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i); + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j); + + /* skip over the border, if any */ + i += img->Border; + j += img->Border; + + switch (img->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[ j * imgWidth + i ]; + palette_sample(tObj, index, rgba); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[ j * imgWidth + i ]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[ j * imgWidth + i ]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + ((j * imgWidth + i) << 1); + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + (j * imgWidth + i) * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + ((j * imgWidth + i) << 2); + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in sample_2d_nearest"); + } +} + + + +/* + * Return the texture sample for coordinate (s,t) using GL_LINEAR filter. + * New sampling code contributed by Lynn Quam <[email protected]>. + */ +static void sample_2d_linear( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, GLfloat t, + GLchan rgba[] ) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + GLint i0, j0, i1, j1; + GLuint useBorderColor; + GLfloat u, v; + + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1); + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1); + + useBorderColor = 0; + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + } + else { + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + } + + { + const GLfloat a = myFrac(u); + const GLfloat b = myFrac(v); + /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */ + const GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * WEIGHT_SCALE + 0.5F); + const GLint w10 = (GLint) ( a *(1.0F-b) * WEIGHT_SCALE + 0.5F); + const GLint w01 = (GLint) ((1.0F-a)* b * WEIGHT_SCALE + 0.5F); + const GLint w11 = (GLint) ( a * b * WEIGHT_SCALE + 0.5F); + GLchan t00[4]; + GLchan t10[4]; + GLchan t01[4]; + GLchan t11[4]; + + if (useBorderColor & (I0BIT | J0BIT)) { + COPY_CHAN4(t00, tObj->BorderColor); + } + else { + get_2d_texel( tObj, img, i0, j0, t00 ); + } + if (useBorderColor & (I1BIT | J0BIT)) { + COPY_CHAN4(t10, tObj->BorderColor); + } + else { + get_2d_texel( tObj, img, i1, j0, t10 ); + } + if (useBorderColor & (I0BIT | J1BIT)) { + COPY_CHAN4(t01, tObj->BorderColor); + } + else { + get_2d_texel( tObj, img, i0, j1, t01 ); + } + if (useBorderColor & (I1BIT | J1BIT)) { + COPY_CHAN4(t11, tObj->BorderColor); + } + else { + get_2d_texel( tObj, img, i1, j1, t11 ); + } + + rgba[0] = (GLchan) ((w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]) >> WEIGHT_SHIFT); + rgba[1] = (GLchan) ((w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]) >> WEIGHT_SHIFT); + rgba[2] = (GLchan) ((w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]) >> WEIGHT_SHIFT); + rgba[3] = (GLchan) ((w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]) >> WEIGHT_SHIFT); + } + +} + + + +static void +sample_2d_nearest_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_2d_nearest( tObj, tObj->Image[level], s, t, rgba ); +} + + + +static void +sample_2d_linear_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_2d_linear( tObj, tObj->Image[level], s, t, rgba ); +} + + + +static void +sample_2d_nearest_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_2d_nearest( tObj, tObj->Image[tObj->P], s, t, rgba ); + } + else { + GLchan t0[4], t1[4]; /* texels */ + const GLfloat f = myFrac(lambda); + sample_2d_nearest( tObj, tObj->Image[level ], s, t, t0 ); + sample_2d_nearest( tObj, tObj->Image[level+1], s, t, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + + +static void +sample_2d_linear_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat lambda, + GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_2d_linear( tObj, tObj->Image[tObj->P], s, t, rgba ); + } + else { + GLchan t0[4], t1[4]; /* texels */ + const GLfloat f = myFrac(lambda); + sample_2d_linear( tObj, tObj->Image[level ], s, t, t0 ); + sample_2d_linear( tObj, tObj->Image[level+1], s, t, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + + +static void sample_nearest_2d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) u; + (void) lambda; + for (i=0;i<n;i++) { + sample_2d_nearest( tObj, image, s[i], t[i], rgba[i] ); + } +} + + + +static void sample_linear_2d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) u; + (void) lambda; + for (i=0;i<n;i++) { + sample_2d_linear( tObj, image, s[i], t[i], rgba[i] ); + } +} + + +/* + * Given an (s,t) texture coordinate and lambda (level of detail) value, + * return a texture sample. + */ +static void sample_lambda_2d( const struct gl_texture_object *tObj, + GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + (void) u; + for (i=0;i<n;i++) { + if (lambda[i] > tObj->MinMagThresh) { + /* minification */ + switch (tObj->MinFilter) { + case GL_NEAREST: + sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] ); + break; + case GL_LINEAR: + sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_2d_nearest_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_2d_linear_mipmap_nearest( tObj, s[i], t[i], lambda[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_2d_nearest_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_2d_linear_mipmap_linear( tObj, s[i], t[i], lambda[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad min filter in sample_2d_texture"); + return; + } + } + else { + /* magnification */ + switch (tObj->MagFilter) { + case GL_NEAREST: + sample_2d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] ); + break; + case GL_LINEAR: + sample_2d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad mag filter in sample_2d_texture"); + } + } + } +} + + +/* + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border + * Format = GL_RGB + */ +static void opt_sample_rgb_2d( const struct gl_texture_object *tObj, + GLuint n, const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint k; + (void) u; + (void) lambda; + ASSERT(tObj->WrapS==GL_REPEAT); + ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(tObj->MinFilter==GL_NEAREST); + ASSERT(tObj->MagFilter==GL_NEAREST); + ASSERT(img->Border==0); + ASSERT(img->Format==GL_RGB); + + /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */ + for (k=0;k<n;k++) { + GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask; + GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask; + GLint pos = (j << shift) | i; + GLchan *texel = img->Data + pos + pos + pos; /* pos*3 */ + rgba[k][RCOMP] = texel[0]; + rgba[k][GCOMP] = texel[1]; + rgba[k][BCOMP] = texel[2]; + } +} + + +/* + * Optimized 2-D texture sampling: + * S and T wrap mode == GL_REPEAT + * GL_NEAREST min/mag filter + * No border + * Format = GL_RGBA + */ +static void opt_sample_rgba_2d( const struct gl_texture_object *tObj, + GLuint n, const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + const struct gl_texture_image *img = tObj->Image[tObj->BaseLevel]; + const GLfloat width = (GLfloat) img->Width; + const GLfloat height = (GLfloat) img->Height; + const GLint colMask = img->Width - 1; + const GLint rowMask = img->Height - 1; + const GLint shift = img->WidthLog2; + GLuint k; + (void) u; + (void) lambda; + ASSERT(tObj->WrapS==GL_REPEAT); + ASSERT(tObj->WrapT==GL_REPEAT); + ASSERT(tObj->MinFilter==GL_NEAREST); + ASSERT(tObj->MagFilter==GL_NEAREST); + ASSERT(img->Border==0); + ASSERT(img->Format==GL_RGBA); + + /* NOTE: negative float->int doesn't floor, add 10000 as to work-around */ + for (k=0;k<n;k++) { + GLint i = (GLint) ((s[k] + 10000.0) * width) & colMask; + GLint j = (GLint) ((t[k] + 10000.0) * height) & rowMask; + GLint pos = (j << shift) | i; + GLchan *texel = img->Data + (pos << 2); /* pos*4 */ + rgba[k][RCOMP] = texel[0]; + rgba[k][GCOMP] = texel[1]; + rgba[k][BCOMP] = texel[2]; + rgba[k][ACOMP] = texel[3]; + } +} + + + +/**********************************************************************/ +/* 3-D Texture Sampling Functions */ +/**********************************************************************/ + +/* + * Given a texture image and an (i,j,k) integer texel coordinate, return the + * texel color. + */ +static void get_3d_texel( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLint i, GLint j, GLint k, + GLchan rgba[4] ) +{ + const GLint width = img->Width; /* includes border */ + const GLint height = img->Height; /* includes border */ + const GLint rectarea = width * height; + const GLchan *texel; + +#ifdef DEBUG + const GLint depth = img->Depth; /* includes border */ + assert(i >= 0); + assert(i < width); + assert(j >= 0); + assert(j < height); + assert(k >= 0); + assert(k < depth); +#endif + + switch (img->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[ rectarea * k + width * j + i ]; + palette_sample(tObj, index, rgba ); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[ rectarea * k + width * j + i ]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[ rectarea * k + width * j + i ]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + ( rectarea * k + width * j + i) * 2; + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + (rectarea * k + width * j + i) * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + (rectarea * k + width * j + i) * 4; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in get_3d_texel"); + } +} + + +/* + * Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter. + */ +static void sample_3d_nearest( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, GLfloat t, GLfloat r, + GLchan rgba[4] ) +{ + const GLint imgWidth = img->Width; /* includes border, if any */ + const GLint imgHeight = img->Height; /* includes border, if any */ + const GLint width = img->Width2; /* without border, power of two */ + const GLint height = img->Height2; /* without border, power of two */ + const GLint depth = img->Depth2; /* without border, power of two */ + const GLint rectarea = imgWidth * imgHeight; + const GLchan *texel; + GLint i, j, k; + + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, s, width, i); + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, t, height, j); + COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapR, r, depth, k); + + switch (tObj->Image[0]->Format) { + case GL_COLOR_INDEX: + { + GLint index = img->Data[ rectarea * k + j * imgWidth + i ]; + palette_sample(tObj, index, rgba ); + return; + } + case GL_ALPHA: + rgba[ACOMP] = img->Data[ rectarea * k + j * imgWidth + i ]; + return; + case GL_LUMINANCE: + case GL_INTENSITY: + rgba[RCOMP] = img->Data[ rectarea * k + j * imgWidth + i ]; + return; + case GL_LUMINANCE_ALPHA: + texel = img->Data + ((rectarea * k + j * imgWidth + i) << 1); + rgba[RCOMP] = texel[0]; + rgba[ACOMP] = texel[1]; + return; + case GL_RGB: + texel = img->Data + ( rectarea * k + j * imgWidth + i) * 3; + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + return; + case GL_RGBA: + texel = img->Data + ((rectarea * k + j * imgWidth + i) << 2); + rgba[RCOMP] = texel[0]; + rgba[GCOMP] = texel[1]; + rgba[BCOMP] = texel[2]; + rgba[ACOMP] = texel[3]; + return; + default: + gl_problem(NULL, "Bad format in sample_3d_nearest"); + } +} + + + +/* + * Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter. + */ +static void sample_3d_linear( const struct gl_texture_object *tObj, + const struct gl_texture_image *img, + GLfloat s, GLfloat t, GLfloat r, + GLchan rgba[4] ) +{ + const GLint width = img->Width2; + const GLint height = img->Height2; + const GLint depth = img->Depth2; + GLint i0, j0, k0, i1, j1, k1; + GLuint useBorderColor; + GLfloat u, v, w; + + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, s, u, width, i0, i1); + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, t, v, height, j0, j1); + COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapR, r, w, depth, k0, k1); + + useBorderColor = 0; + if (img->Border) { + i0 += img->Border; + i1 += img->Border; + j0 += img->Border; + j1 += img->Border; + k0 += img->Border; + k1 += img->Border; + } + else { + /* check if sampling texture border color */ + if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT; + if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT; + if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT; + if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT; + if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT; + if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT; + } + + { + const GLfloat a = myFrac(u); + const GLfloat b = myFrac(v); + const GLfloat c = myFrac(w); + /* compute sample weights in fixed point in [0,WEIGHT_SCALE] */ + GLint w000 = (GLint) ((1.0F-a)*(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F); + GLint w100 = (GLint) ( a *(1.0F-b)*(1.0F-c) * WEIGHT_SCALE + 0.5F); + GLint w010 = (GLint) ((1.0F-a)* b *(1.0F-c) * WEIGHT_SCALE + 0.5F); + GLint w110 = (GLint) ( a * b *(1.0F-c) * WEIGHT_SCALE + 0.5F); + GLint w001 = (GLint) ((1.0F-a)*(1.0F-b)* c * WEIGHT_SCALE + 0.5F); + GLint w101 = (GLint) ( a *(1.0F-b)* c * WEIGHT_SCALE + 0.5F); + GLint w011 = (GLint) ((1.0F-a)* b * c * WEIGHT_SCALE + 0.5F); + GLint w111 = (GLint) ( a * b * c * WEIGHT_SCALE + 0.5F); + + GLchan t000[4], t010[4], t001[4], t011[4]; + GLchan t100[4], t110[4], t101[4], t111[4]; + + if (useBorderColor & (I0BIT | J0BIT | K0BIT)) { + COPY_CHAN4(t000, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i0, j0, k0, t000 ); + } + if (useBorderColor & (I1BIT | J0BIT | K0BIT)) { + COPY_CHAN4(t100, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i1, j0, k0, t100 ); + } + if (useBorderColor & (I0BIT | J1BIT | K0BIT)) { + COPY_CHAN4(t010, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i0, j1, k0, t010 ); + } + if (useBorderColor & (I1BIT | J1BIT | K0BIT)) { + COPY_CHAN4(t110, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i1, j1, k0, t110 ); + } + + if (useBorderColor & (I0BIT | J0BIT | K1BIT)) { + COPY_CHAN4(t001, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i0, j0, k1, t001 ); + } + if (useBorderColor & (I1BIT | J0BIT | K1BIT)) { + COPY_CHAN4(t101, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i1, j0, k1, t101 ); + } + if (useBorderColor & (I0BIT | J1BIT | K1BIT)) { + COPY_CHAN4(t011, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i0, j1, k1, t011 ); + } + if (useBorderColor & (I1BIT | J1BIT | K1BIT)) { + COPY_CHAN4(t111, tObj->BorderColor); + } + else { + get_3d_texel( tObj, img, i1, j1, k1, t111 ); + } + + rgba[0] = (GLchan) ( + (w000*t000[0] + w010*t010[0] + w001*t001[0] + w011*t011[0] + + w100*t100[0] + w110*t110[0] + w101*t101[0] + w111*t111[0] ) + >> WEIGHT_SHIFT); + rgba[1] = (GLchan) ( + (w000*t000[1] + w010*t010[1] + w001*t001[1] + w011*t011[1] + + w100*t100[1] + w110*t110[1] + w101*t101[1] + w111*t111[1] ) + >> WEIGHT_SHIFT); + rgba[2] = (GLchan) ( + (w000*t000[2] + w010*t010[2] + w001*t001[2] + w011*t011[2] + + w100*t100[2] + w110*t110[2] + w101*t101[2] + w111*t111[2] ) + >> WEIGHT_SHIFT); + rgba[3] = (GLchan) ( + (w000*t000[3] + w010*t010[3] + w001*t001[3] + w011*t011[3] + + w100*t100[3] + w110*t110[3] + w101*t101[3] + w111*t111[3] ) + >> WEIGHT_SHIFT); + } +} + + + +static void +sample_3d_nearest_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat r, + GLfloat lambda, GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_3d_nearest( tObj, tObj->Image[level], s, t, r, rgba ); +} + + +static void +sample_3d_linear_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat r, + GLfloat lambda, GLchan rgba[4] ) +{ + GLint level; + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + sample_3d_linear( tObj, tObj->Image[level], s, t, r, rgba ); +} + + +static void +sample_3d_nearest_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat r, + GLfloat lambda, GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_3d_nearest( tObj, tObj->Image[tObj->P], s, t, r, rgba ); + } + else { + GLchan t0[4], t1[4]; /* texels */ + const GLfloat f = myFrac(lambda); + sample_3d_nearest( tObj, tObj->Image[level ], s, t, r, t0 ); + sample_3d_nearest( tObj, tObj->Image[level+1], s, t, r, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + +static void +sample_3d_linear_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat r, + GLfloat lambda, GLchan rgba[4] ) +{ + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + if (level >= tObj->P) { + sample_3d_linear( tObj, tObj->Image[tObj->P], s, t, r, rgba ); + } + else { + GLchan t0[4], t1[4]; /* texels */ + const GLfloat f = myFrac(lambda); + sample_3d_linear( tObj, tObj->Image[level ], s, t, r, t0 ); + sample_3d_linear( tObj, tObj->Image[level+1], s, t, r, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + +static void sample_nearest_3d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) lambda; + for (i=0;i<n;i++) { + sample_3d_nearest( tObj, image, s[i], t[i], u[i], rgba[i] ); + } +} + + + +static void sample_linear_3d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + struct gl_texture_image *image = tObj->Image[tObj->BaseLevel]; + (void) lambda; + for (i=0;i<n;i++) { + sample_3d_linear( tObj, image, s[i], t[i], u[i], rgba[i] ); + } +} + + +/* + * Given an (s,t,r) texture coordinate and lambda (level of detail) value, + * return a texture sample. + */ +static void sample_lambda_3d( const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4] ) +{ + GLuint i; + + for (i=0;i<n;i++) { + + if (lambda[i] > tObj->MinMagThresh) { + /* minification */ + switch (tObj->MinFilter) { + case GL_NEAREST: + sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] ); + break; + case GL_LINEAR: + sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_3d_nearest_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_3d_linear_mipmap_nearest( tObj, s[i], t[i], u[i], lambda[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_3d_nearest_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_3d_linear_mipmap_linear( tObj, s[i], t[i], u[i], lambda[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad min filterin sample_3d_texture"); + } + } + else { + /* magnification */ + switch (tObj->MagFilter) { + case GL_NEAREST: + sample_3d_nearest( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] ); + break; + case GL_LINEAR: + sample_3d_linear( tObj, tObj->Image[tObj->BaseLevel], s[i], t[i], u[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad mag filter in sample_3d_texture"); + } + } + } +} + + +/**********************************************************************/ +/* Texture Cube Map Sampling Functions */ +/**********************************************************************/ + +/* + * Choose one of six sides of a texture cube map given the texture + * coord (rx,ry,rz). Return pointer to corresponding array of texture + * images. + */ +static const struct gl_texture_image ** +choose_cube_face(const struct gl_texture_object *texObj, + GLfloat rx, GLfloat ry, GLfloat rz, + GLfloat *newS, GLfloat *newT) +{ +/* + major axis + direction target sc tc ma + ---------- ------------------------------- --- --- --- + +rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx + -rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx + +ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry + -ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry + +rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz + -rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz +*/ + const struct gl_texture_image **imgArray; + const GLfloat arx = ABSF(rx), ary = ABSF(ry), arz = ABSF(rz); + GLfloat sc, tc, ma; + + if (arx > ary && arx > arz) { + if (rx >= 0.0F) { + imgArray = (const struct gl_texture_image **) texObj->Image; + sc = -rz; + tc = -ry; + ma = arx; + } + else { + imgArray = (const struct gl_texture_image **) texObj->NegX; + sc = rz; + tc = -ry; + ma = arx; + } + } + else if (ary > arx && ary > arz) { + if (ry >= 0.0F) { + imgArray = (const struct gl_texture_image **) texObj->PosY; + sc = rx; + tc = rz; + ma = ary; + } + else { + imgArray = (const struct gl_texture_image **) texObj->NegY; + sc = rx; + tc = -rz; + ma = ary; + } + } + else { + if (rz > 0.0F) { + imgArray = (const struct gl_texture_image **) texObj->PosZ; + sc = rx; + tc = -ry; + ma = arz; + } + else { + imgArray = (const struct gl_texture_image **) texObj->NegZ; + sc = -rx; + tc = -ry; + ma = arz; + } + } + + *newS = ( sc / ma + 1.0F ) * 0.5F; + *newT = ( tc / ma + 1.0F ) * 0.5F; + return imgArray; +} + + +static void +sample_nearest_cube(const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newS, newT; + images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT); + sample_2d_nearest( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] ); + } +} + + +static void +sample_linear_cube(const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4]) +{ + GLuint i; + (void) lambda; + for (i = 0; i < n; i++) { + const struct gl_texture_image **images; + GLfloat newS, newT; + images = choose_cube_face(tObj, s[i], t[i], u[i], &newS, &newT); + sample_2d_linear( tObj, images[tObj->BaseLevel], newS, newT, rgba[i] ); + } +} + + +static void +sample_cube_nearest_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat u, + GLfloat lambda, GLchan rgba[4] ) +{ + const struct gl_texture_image **images; + GLfloat newS, newT; + GLint level; + + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + + images = choose_cube_face(tObj, s, t, u, &newS, &newT); + sample_2d_nearest( tObj, images[level], newS, newT, rgba ); +} + + +static void +sample_cube_linear_mipmap_nearest( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat u, + GLfloat lambda, GLchan rgba[4] ) +{ + const struct gl_texture_image **images; + GLfloat newS, newT; + GLint level; + + COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level); + + images = choose_cube_face(tObj, s, t, u, &newS, &newT); + sample_2d_linear( tObj, images[level], newS, newT, rgba ); +} + + +static void +sample_cube_nearest_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat u, + GLfloat lambda, GLchan rgba[4] ) +{ + const struct gl_texture_image **images; + GLfloat newS, newT; + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + images = choose_cube_face(tObj, s, t, u, &newS, &newT); + + if (level >= tObj->P) { + sample_2d_nearest( tObj, images[tObj->P], newS, newT, rgba ); + } + else { + GLchan t0[4], t1[4]; /* texels */ + const GLfloat f = myFrac(lambda); + sample_2d_nearest( tObj, images[level ], newS, newT, t0 ); + sample_2d_nearest( tObj, images[level+1], newS, newT, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + +static void +sample_cube_linear_mipmap_linear( const struct gl_texture_object *tObj, + GLfloat s, GLfloat t, GLfloat u, + GLfloat lambda, GLchan rgba[4] ) +{ + const struct gl_texture_image **images; + GLfloat newS, newT; + GLint level; + + COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda, level); + + images = choose_cube_face(tObj, s, t, u, &newS, &newT); + + if (level >= tObj->P) { + sample_2d_linear( tObj, images[tObj->P], newS, newT, rgba ); + } + else { + GLchan t0[4], t1[4]; + const GLfloat f = myFrac(lambda); + sample_2d_linear( tObj, images[level ], newS, newT, t0 ); + sample_2d_linear( tObj, images[level+1], newS, newT, t1 ); + rgba[RCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]); + rgba[GCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]); + rgba[BCOMP] = (GLchan) (GLint) ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]); + rgba[ACOMP] = (GLchan) (GLint) ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]); + } +} + + +static void +sample_lambda_cube(const struct gl_texture_object *tObj, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat u[], const GLfloat lambda[], + GLchan rgba[][4]) +{ + GLuint i; + + for (i = 0; i < n; i++) { + if (lambda[i] > tObj->MinMagThresh) { + /* minification */ + switch (tObj->MinFilter) { + case GL_NEAREST: + { + const struct gl_texture_image **images; + GLfloat newS, newT; + images = choose_cube_face(tObj, s[i], t[i], u[i], + &newS, &newT); + sample_2d_nearest( tObj, images[tObj->BaseLevel], + newS, newT, rgba[i] ); + } + break; + case GL_LINEAR: + { + const struct gl_texture_image **images; + GLfloat newS, newT; + images = choose_cube_face(tObj, s[i], t[i], u[i], + &newS, &newT); + sample_2d_linear( tObj, images[tObj->BaseLevel], + newS, newT, rgba[i] ); + } + break; + case GL_NEAREST_MIPMAP_NEAREST: + sample_cube_nearest_mipmap_nearest( tObj, s[i], t[i], u[i], + lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_NEAREST: + sample_cube_linear_mipmap_nearest( tObj, s[i], t[i], u[i], + lambda[i], rgba[i] ); + break; + case GL_NEAREST_MIPMAP_LINEAR: + sample_cube_nearest_mipmap_linear( tObj, s[i], t[i], u[i], + lambda[i], rgba[i] ); + break; + case GL_LINEAR_MIPMAP_LINEAR: + sample_cube_linear_mipmap_linear( tObj, s[i], t[i], u[i], + lambda[i], rgba[i] ); + break; + default: + gl_problem(NULL, "Bad min filter in sample_lambda_cube"); + } + } + else { + /* magnification */ + const struct gl_texture_image **images; + GLfloat newS, newT; + images = choose_cube_face(tObj, s[i], t[i], u[i], + &newS, &newT); + switch (tObj->MagFilter) { + case GL_NEAREST: + sample_2d_nearest( tObj, images[tObj->BaseLevel], + newS, newT, rgba[i] ); + break; + case GL_LINEAR: + sample_2d_linear( tObj, images[tObj->BaseLevel], + newS, newT, rgba[i] ); + break; + default: + gl_problem(NULL, "Bad mag filter in sample_lambda_cube"); + } + } + } +} + + +/**********************************************************************/ +/* Texture Sampling Setup */ +/**********************************************************************/ + + +/* + * Setup the texture sampling function for this texture object. + */ +void +_swrast_set_texture_sampler( struct gl_texture_object *t ) +{ + if (!t->Complete) { + t->SampleFunc = NULL; + } + else { + GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter); + + if (needLambda) { + /* Compute min/mag filter threshold */ + if (t->MagFilter==GL_LINEAR + && (t->MinFilter==GL_NEAREST_MIPMAP_NEAREST || + t->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) { + t->MinMagThresh = 0.5F; + } + else { + t->MinMagThresh = 0.0F; + } + } + + switch (t->Dimensions) { + case 1: + if (needLambda) { + t->SampleFunc = sample_lambda_1d; + } + else if (t->MinFilter==GL_LINEAR) { + t->SampleFunc = sample_linear_1d; + } + else { + ASSERT(t->MinFilter==GL_NEAREST); + t->SampleFunc = sample_nearest_1d; + } + break; + case 2: + if (needLambda) { + t->SampleFunc = sample_lambda_2d; + } + else if (t->MinFilter==GL_LINEAR) { + t->SampleFunc = sample_linear_2d; + } + else { + ASSERT(t->MinFilter==GL_NEAREST); + if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT + && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGB) { + t->SampleFunc = opt_sample_rgb_2d; + } + else if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT + && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGBA) { + t->SampleFunc = opt_sample_rgba_2d; + } + else + t->SampleFunc = sample_nearest_2d; + } + break; + case 3: + if (needLambda) { + t->SampleFunc = sample_lambda_3d; + } + else if (t->MinFilter==GL_LINEAR) { + t->SampleFunc = sample_linear_3d; + } + else { + ASSERT(t->MinFilter==GL_NEAREST); + t->SampleFunc = sample_nearest_3d; + } + break; + case 6: /* cube map */ + if (needLambda) { + t->SampleFunc = sample_lambda_cube; + } + else if (t->MinFilter==GL_LINEAR) { + t->SampleFunc = sample_linear_cube; + } + else { + ASSERT(t->MinFilter==GL_NEAREST); + t->SampleFunc = sample_nearest_cube; + } + break; + default: + gl_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler"); + } + } +} + + +#define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) ) + +static INLINE void +_mesa_texture_combine(const GLcontext *ctx, + const struct gl_texture_unit *textureUnit, + GLuint n, + GLchan (*primary_rgba)[4], + GLchan (*texel)[4], + GLchan (*rgba)[4]) +{ + GLchan ccolor [3][3*MAX_WIDTH][4]; + GLchan (*argRGB [3])[4]; + GLchan (*argA [3])[4]; + GLuint i, j; + const GLuint RGBshift = textureUnit->CombineScaleShiftRGB; + const GLuint Ashift = textureUnit->CombineScaleShiftA; + + ASSERT(ctx->Extensions.EXT_texture_env_combine); + + for (j = 0; j < 3; j++) { + switch (textureUnit->CombineSourceA[j]) { + case GL_TEXTURE: + argA[j] = texel; + break; + case GL_PRIMARY_COLOR_EXT: + argA[j] = primary_rgba; + break; + case GL_PREVIOUS_EXT: + argA[j] = rgba; + break; + case GL_CONSTANT_EXT: + { + GLchan (*c)[4] = ccolor[j]; + GLchan alpha = FLOAT_TO_CHAN(textureUnit->EnvColor[3]); + for (i = 0; i < n; i++) + c[i][ACOMP] = alpha; + argA[j] = ccolor[j]; + } + break; + default: + gl_problem(NULL, "invalid combine source"); + } + + switch (textureUnit->CombineSourceRGB[j]) { + case GL_TEXTURE: + argRGB[j] = texel; + break; + case GL_PRIMARY_COLOR_EXT: + argRGB[j] = primary_rgba; + break; + case GL_PREVIOUS_EXT: + argRGB[j] = rgba; + break; + case GL_CONSTANT_EXT: + { + GLchan (*c)[4] = ccolor[j]; + const GLchan red = FLOAT_TO_CHAN(textureUnit->EnvColor[0]); + const GLchan green = FLOAT_TO_CHAN(textureUnit->EnvColor[1]); + const GLchan blue = FLOAT_TO_CHAN(textureUnit->EnvColor[2]); + for (i = 0; i < n; i++) { + c[i][RCOMP] = red; + c[i][GCOMP] = green; + c[i][BCOMP] = blue; + } + argRGB[j] = ccolor[j]; + } + break; + default: + gl_problem(NULL, "invalid combine source"); + } + + if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) { + GLchan (*src)[4] = argRGB[j]; + GLchan (*dst)[4] = ccolor[j]; + + argRGB[j] = ccolor[j]; + + if (textureUnit->CombineOperandRGB[j] == GL_ONE_MINUS_SRC_COLOR) { + for (i = 0; i < n; i++) { + dst[i][RCOMP] = CHAN_MAX - src[i][RCOMP]; + dst[i][GCOMP] = CHAN_MAX - src[i][GCOMP]; + dst[i][BCOMP] = CHAN_MAX - src[i][BCOMP]; + } + } + else if (textureUnit->CombineOperandRGB[j] == GL_SRC_ALPHA) { + src = argA[j]; + for (i = 0; i < n; i++) { + dst[i][RCOMP] = src[i][ACOMP]; + dst[i][GCOMP] = src[i][ACOMP]; + dst[i][BCOMP] = src[i][ACOMP]; + } + } + else { /* GL_ONE_MINUS_SRC_ALPHA */ + src = argA[j]; + for (i = 0; i < n; i++) { + dst[i][RCOMP] = CHAN_MAX - src[i][ACOMP]; + dst[i][GCOMP] = CHAN_MAX - src[i][ACOMP]; + dst[i][BCOMP] = CHAN_MAX - src[i][ACOMP]; + } + } + } + + if (textureUnit->CombineOperandA[j] == GL_ONE_MINUS_SRC_ALPHA) { + GLchan (*src)[4] = argA[j]; + GLchan (*dst)[4] = ccolor[j]; + argA[j] = ccolor[j]; + for (i = 0; i < n; i++) { + dst[i][ACOMP] = CHAN_MAX - src[i][ACOMP]; + } + } + + if (textureUnit->CombineModeRGB == GL_REPLACE && + textureUnit->CombineModeA == GL_REPLACE) { + break; /* done, we need only arg0 */ + } + + if (j == 1 && + textureUnit->CombineModeRGB != GL_INTERPOLATE_EXT && + textureUnit->CombineModeA != GL_INTERPOLATE_EXT) { + break; /* arg0 and arg1 are done. we don't need arg2. */ + } + } + + switch (textureUnit->CombineModeRGB) { + case GL_REPLACE: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0]; + if (RGBshift) { + for (i = 0; i < n; i++) { + GLuint r = (GLuint) arg0[i][RCOMP] << RGBshift; + GLuint g = (GLuint) arg0[i][GCOMP] << RGBshift; + GLuint b = (GLuint) arg0[i][BCOMP] << RGBshift; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + } + } + else { + for (i = 0; i < n; i++) { + rgba[i][RCOMP] = arg0[i][RCOMP]; + rgba[i][GCOMP] = arg0[i][GCOMP]; + rgba[i][BCOMP] = arg0[i][BCOMP]; + } + } + } + break; + case GL_MODULATE: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1]; + const GLint shift = 8 - RGBshift; + for (i = 0; i < n; i++) { + GLuint r = PROD(arg0[i][0], arg1[i][RCOMP]) >> shift; + GLuint g = PROD(arg0[i][1], arg1[i][GCOMP]) >> shift; + GLuint b = PROD(arg0[i][2], arg1[i][BCOMP]) >> shift; + rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); + } + } + break; + case GL_ADD: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1]; + for (i = 0; i < n; i++) { + GLint r = ((GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP]) << RGBshift; + GLint g = ((GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP]) << RGBshift; + GLint b = ((GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP]) << RGBshift; + rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); + } + } + break; + case GL_ADD_SIGNED_EXT: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1]; + for (i = 0; i < n; i++) { + GLint r = (GLint) arg0[i][RCOMP] + (GLint) arg1[i][RCOMP] - 128; + GLint g = (GLint) arg0[i][GCOMP] + (GLint) arg1[i][GCOMP] - 128; + GLint b = (GLint) arg0[i][BCOMP] + (GLint) arg1[i][BCOMP] - 128; + r = (r < 0) ? 0 : r << RGBshift; + g = (g < 0) ? 0 : g << RGBshift; + b = (b < 0) ? 0 : b << RGBshift; + rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); + } + } + break; + case GL_INTERPOLATE_EXT: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1]; + const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2]; + const GLint shift = 8 - RGBshift; + for (i = 0; i < n; i++) { + GLuint r = (PROD(arg0[i][RCOMP], arg2[i][RCOMP]) + + PROD(arg1[i][RCOMP], CHAN_MAX - arg2[i][RCOMP])) + >> shift; + GLuint g = (PROD(arg0[i][GCOMP], arg2[i][GCOMP]) + + PROD(arg1[i][GCOMP], CHAN_MAX - arg2[i][GCOMP])) + >> shift; + GLuint b = (PROD(arg0[i][BCOMP], arg2[i][BCOMP]) + + PROD(arg1[i][BCOMP], CHAN_MAX - arg2[i][BCOMP])) + >> shift; + rgba[i][RCOMP] = (GLchan) MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = (GLchan) MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = (GLchan) MIN2(b, CHAN_MAX); + } + } + break; + default: + gl_problem(NULL, "invalid combine mode"); + } + + switch (textureUnit->CombineModeA) { + case GL_REPLACE: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0]; + if (Ashift) { + for (i = 0; i < n; i++) { + GLuint a = (GLuint) arg0[i][ACOMP] << Ashift; + rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX); + } + } + else { + for (i = 0; i < n; i++) { + rgba[i][ACOMP] = arg0[i][ACOMP]; + } + } + } + break; + case GL_MODULATE: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1]; + const GLint shift = 8 - Ashift; + for (i = 0; i < n; i++) { + GLuint a = (PROD(arg0[i][ACOMP], arg1[i][ACOMP]) >> shift); + rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX); + } + } + break; + case GL_ADD: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1]; + for (i = 0; i < n; i++) { + GLint a = ((GLint) arg0[i][ACOMP] + arg1[i][ACOMP]) << Ashift; + rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX); + } + } + break; + case GL_ADD_SIGNED_EXT: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1]; + for (i = 0; i < n; i++) { + GLint a = (GLint) arg0[i][ACOMP] + (GLint) arg1[i][ACOMP] - 128; + a = (a < 0) ? 0 : a << Ashift; + rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX); + } + } + break; + case GL_INTERPOLATE_EXT: + { + const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0]; + const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1]; + const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2]; + const GLint shift = 8 - Ashift; + for (i=0; i<n; i++) { + GLuint a = (PROD(arg0[i][ACOMP], arg2[i][ACOMP]) + + PROD(arg1[i][ACOMP], CHAN_MAX - arg2[i][ACOMP])) + >> shift; + rgba[i][ACOMP] = (GLchan) MIN2(a, CHAN_MAX); + } + } + break; + default: + gl_problem(NULL, "invalid combine mode"); + } +} +#undef PROD + + + +/**********************************************************************/ +/* Texture Application */ +/**********************************************************************/ + + +/* + * Combine incoming fragment color with texel color to produce output color. + * Input: textureUnit - pointer to texture unit to apply + * format - base internal texture format + * n - number of fragments + * primary_rgba - primary colors (may be rgba for single texture) + * texels - array of texel colors + * InOut: rgba - incoming fragment colors modified by texel colors + * according to the texture environment mode. + */ +static void +apply_texture( const GLcontext *ctx, + const struct gl_texture_unit *texUnit, + GLuint n, + GLchan primary_rgba[][4], GLchan texel[][4], + GLchan rgba[][4] ) +{ + GLint baseLevel; + GLuint i; + GLint Rc, Gc, Bc, Ac; + GLenum format; + + ASSERT(texUnit); + ASSERT(texUnit->Current); + + baseLevel = texUnit->Current->BaseLevel; + ASSERT(texUnit->Current->Image[baseLevel]); + + format = texUnit->Current->Image[baseLevel]->Format; + + if (format==GL_COLOR_INDEX) { + format = GL_RGBA; /* XXXX a hack! */ + } + + switch (texUnit->EnvMode) { + case GL_REPLACE: + switch (format) { + case GL_ALPHA: + for (i=0;i<n;i++) { + /* Cv = Cf */ + /* Av = At */ + rgba[i][ACOMP] = texel[i][ACOMP]; + } + break; + case GL_LUMINANCE: + for (i=0;i<n;i++) { + /* Cv = Lt */ + GLchan Lt = texel[i][RCOMP]; + rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt; + /* Av = Af */ + } + break; + case GL_LUMINANCE_ALPHA: + for (i=0;i<n;i++) { + GLchan Lt = texel[i][RCOMP]; + /* Cv = Lt */ + rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = Lt; + /* Av = At */ + rgba[i][ACOMP] = texel[i][ACOMP]; + } + break; + case GL_INTENSITY: + for (i=0;i<n;i++) { + /* Cv = It */ + GLchan It = texel[i][RCOMP]; + rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = It; + /* Av = It */ + rgba[i][ACOMP] = It; + } + break; + case GL_RGB: + for (i=0;i<n;i++) { + /* Cv = Ct */ + rgba[i][RCOMP] = texel[i][RCOMP]; + rgba[i][GCOMP] = texel[i][GCOMP]; + rgba[i][BCOMP] = texel[i][BCOMP]; + /* Av = Af */ + } + break; + case GL_RGBA: + for (i=0;i<n;i++) { + /* Cv = Ct */ + rgba[i][RCOMP] = texel[i][RCOMP]; + rgba[i][GCOMP] = texel[i][GCOMP]; + rgba[i][BCOMP] = texel[i][BCOMP]; + /* Av = At */ + rgba[i][ACOMP] = texel[i][ACOMP]; + } + break; + default: + gl_problem(ctx, "Bad format (GL_REPLACE) in apply_texture"); + return; + } + break; + + case GL_MODULATE: + switch (format) { + case GL_ALPHA: + for (i=0;i<n;i++) { + /* Cv = Cf */ + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] ); + } + break; + case GL_LUMINANCE: + for (i=0;i<n;i++) { + /* Cv = LtCf */ + GLchan Lt = texel[i][RCOMP]; + rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt ); + rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt ); + rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt ); + /* Av = Af */ + } + break; + case GL_LUMINANCE_ALPHA: + for (i=0;i<n;i++) { + /* Cv = CfLt */ + GLchan Lt = texel[i][RCOMP]; + rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], Lt ); + rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], Lt ); + rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], Lt ); + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] ); + } + break; + case GL_INTENSITY: + for (i=0;i<n;i++) { + /* Cv = CfIt */ + GLchan It = texel[i][RCOMP]; + rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It ); + rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It ); + rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It ); + /* Av = AfIt */ + rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It ); + } + break; + case GL_RGB: + for (i=0;i<n;i++) { + /* Cv = CfCt */ + rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] ); + rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] ); + rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] ); + /* Av = Af */ + } + break; + case GL_RGBA: + for (i=0;i<n;i++) { + /* Cv = CfCt */ + rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] ); + rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] ); + rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] ); + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] ); + } + break; + default: + gl_problem(ctx, "Bad format (GL_MODULATE) in apply_texture"); + return; + } + break; + + case GL_DECAL: + switch (format) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + /* undefined */ + break; + case GL_RGB: + for (i=0;i<n;i++) { + /* Cv = Ct */ + rgba[i][RCOMP] = texel[i][RCOMP]; + rgba[i][GCOMP] = texel[i][GCOMP]; + rgba[i][BCOMP] = texel[i][BCOMP]; + /* Av = Af */ + } + break; + case GL_RGBA: + for (i=0;i<n;i++) { + /* Cv = Cf(1-At) + CtAt */ + GLint t = texel[i][ACOMP], s = CHAN_MAX - t; + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t); + /* Av = Af */ + } + break; + default: + gl_problem(ctx, "Bad format (GL_DECAL) in apply_texture"); + return; + } + break; + + case GL_BLEND: + Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF); + Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF); + Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF); + Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF); + switch (format) { + case GL_ALPHA: + for (i=0;i<n;i++) { + /* Cv = Cf */ + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]); + } + break; + case GL_LUMINANCE: + for (i=0;i<n;i++) { + /* Cv = Cf(1-Lt) + CcLt */ + GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt; + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt); + /* Av = Af */ + } + break; + case GL_LUMINANCE_ALPHA: + for (i=0;i<n;i++) { + /* Cv = Cf(1-Lt) + CcLt */ + GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt; + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt); + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]); + } + break; + case GL_INTENSITY: + for (i=0;i<n;i++) { + /* Cv = Cf(1-It) + CcLt */ + GLchan It = texel[i][RCOMP], s = CHAN_MAX - It; + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It); + /* Av = Af(1-It) + Ac*It */ + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It); + } + break; + case GL_RGB: + for (i=0;i<n;i++) { + /* Cv = Cf(1-Ct) + CcCt */ + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]); + /* Av = Af */ + } + break; + case GL_RGBA: + for (i=0;i<n;i++) { + /* Cv = Cf(1-Ct) + CcCt */ + rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]); + rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]); + rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]); + /* Av = AfAt */ + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]); + } + break; + default: + gl_problem(ctx, "Bad format (GL_BLEND) in apply_texture"); + return; + } + break; + + case GL_ADD: /* GL_EXT_texture_add_env */ + switch (format) { + case GL_ALPHA: + for (i=0;i<n;i++) { + /* Rv = Rf */ + /* Gv = Gf */ + /* Bv = Bf */ + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]); + } + break; + case GL_LUMINANCE: + for (i=0;i<n;i++) { + GLuint Lt = texel[i][RCOMP]; + GLuint r = rgba[i][RCOMP] + Lt; + GLuint g = rgba[i][GCOMP] + Lt; + GLuint b = rgba[i][BCOMP] + Lt; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + /* Av = Af */ + } + break; + case GL_LUMINANCE_ALPHA: + for (i=0;i<n;i++) { + GLuint Lt = texel[i][RCOMP]; + GLuint r = rgba[i][RCOMP] + Lt; + GLuint g = rgba[i][GCOMP] + Lt; + GLuint b = rgba[i][BCOMP] + Lt; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]); + } + break; + case GL_INTENSITY: + for (i=0;i<n;i++) { + GLchan It = texel[i][RCOMP]; + GLuint r = rgba[i][RCOMP] + It; + GLuint g = rgba[i][GCOMP] + It; + GLuint b = rgba[i][BCOMP] + It; + GLuint a = rgba[i][ACOMP] + It; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + rgba[i][ACOMP] = MIN2(a, CHAN_MAX); + } + break; + case GL_RGB: + for (i=0;i<n;i++) { + GLuint r = rgba[i][RCOMP] + texel[i][RCOMP]; + GLuint g = rgba[i][GCOMP] + texel[i][GCOMP]; + GLuint b = rgba[i][BCOMP] + texel[i][BCOMP]; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + /* Av = Af */ + } + break; + case GL_RGBA: + for (i=0;i<n;i++) { + GLuint r = rgba[i][RCOMP] + texel[i][RCOMP]; + GLuint g = rgba[i][GCOMP] + texel[i][GCOMP]; + GLuint b = rgba[i][BCOMP] + texel[i][BCOMP]; + rgba[i][RCOMP] = MIN2(r, CHAN_MAX); + rgba[i][GCOMP] = MIN2(g, CHAN_MAX); + rgba[i][BCOMP] = MIN2(b, CHAN_MAX); + rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]); + } + break; + default: + gl_problem(ctx, "Bad format (GL_ADD) in apply_texture"); + return; + } + break; + + case GL_COMBINE_EXT: /* GL_EXT_combine_ext; we modify texel array */ + switch (format) { + case GL_ALPHA: + for (i=0;i<n;i++) + texel[i][RCOMP] = texel[i][GCOMP] = texel[i][BCOMP] = 0; + break; + case GL_LUMINANCE: + for (i=0;i<n;i++) { + /* Cv = Lt */ + GLchan Lt = texel[i][RCOMP]; + texel[i][GCOMP] = texel[i][BCOMP] = Lt; + /* Av = 1 */ + texel[i][ACOMP] = CHAN_MAX; + } + break; + case GL_LUMINANCE_ALPHA: + for (i=0;i<n;i++) { + GLchan Lt = texel[i][RCOMP]; + /* Cv = Lt */ + texel[i][GCOMP] = texel[i][BCOMP] = Lt; + } + break; + case GL_INTENSITY: + for (i=0;i<n;i++) { + /* Cv = It */ + GLchan It = texel[i][RCOMP]; + texel[i][GCOMP] = texel[i][BCOMP] = It; + /* Av = It */ + texel[i][ACOMP] = It; + } + break; + case GL_RGB: + for (i=0;i<n;i++) { + /* Av = 1 */ + texel[i][ACOMP] = CHAN_MAX; + } + break; + case GL_RGBA: /* do nothing. */ + break; + default: + gl_problem(ctx, "Bad format in apply_texture (GL_COMBINE_EXT)"); + return; + } + _mesa_texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba); + break; + + default: + gl_problem(ctx, "Bad env mode in apply_texture"); + return; + } +} + + + +/* + * Apply a unit of texture mapping to the incoming fragments. + */ +void gl_texture_pixels( GLcontext *ctx, GLuint texUnit, GLuint n, + const GLfloat s[], const GLfloat t[], + const GLfloat r[], GLfloat lambda[], + GLchan primary_rgba[][4], GLchan rgba[][4] ) +{ + const GLuint mask = TEXTURE0_ANY << (texUnit * 4); + + if (ctx->Texture.ReallyEnabled & mask) { + const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit]; + + if (textureUnit->Current && textureUnit->Current->SampleFunc) { + GLchan texel[PB_SIZE][4]; + + if (textureUnit->LodBias != 0.0F) { + /* apply LOD bias, but don't clamp yet */ + GLuint i; + for (i=0;i<n;i++) { + lambda[i] += textureUnit->LodBias; + } + } + + if (textureUnit->Current->MinLod != -1000.0 + || textureUnit->Current->MaxLod != 1000.0) { + /* apply LOD clamping to lambda */ + GLfloat min = textureUnit->Current->MinLod; + GLfloat max = textureUnit->Current->MaxLod; + GLuint i; + for (i=0;i<n;i++) { + GLfloat l = lambda[i]; + lambda[i] = CLAMP(l, min, max); + } + } + + /* fetch texture images from device driver, if needed */ + if (ctx->Driver.GetTexImage) { + if (!_mesa_get_teximages_from_driver(ctx, textureUnit->Current)) { + return; + } + } + + /* Sample the texture. */ + (*textureUnit->Current->SampleFunc)( textureUnit->Current, n, + s, t, r, lambda, texel ); + + apply_texture( ctx, textureUnit, n, primary_rgba, texel, rgba ); + } + } +} |