-/* $Id: s_texture.c,v 1.58 2002/04/04 16:56:24 brianp Exp $ */
+/* $Id: s_texture.c,v 1.75 2002/11/12 19:27:24 brianp Exp $ */
/*
* Mesa 3-D graphics library
- * Version: 4.1
+ * Version: 5.0
*
* Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
*
#include "colormac.h"
#include "macros.h"
#include "mmath.h"
-#include "mem.h"
+#include "imports.h"
#include "texformat.h"
#include "teximage.h"
U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \
else \
U = S - (GLfloat) flr; /* flr is even */ \
+ U = (U * SIZE) - 0.5F; \
+ I0 = IFLOOR(U); \
+ I1 = I0 + 1; \
+ if (I0 < 0) \
+ I0 = 0; \
+ if (I1 >= (GLint) SIZE) \
+ I1 = SIZE - 1; \
+ } \
+ else if (wrapMode == GL_MIRROR_CLAMP_ATI) { \
+ U = (GLfloat) fabs(S); \
+ if (U >= 1.0F) \
+ U = (GLfloat) SIZE; \
+ else \
+ U *= SIZE; \
+ U -= 0.5F; \
+ I0 = IFLOOR(U); \
+ I1 = I0 + 1; \
+ } \
+ else if (wrapMode == GL_MIRROR_CLAMP_TO_EDGE_ATI) { \
+ U = (GLfloat) fabs(S); \
+ if (U >= 1.0F) \
+ U = (GLfloat) SIZE; \
+ else \
+ U *= SIZE; \
+ U -= 0.5F; \
I0 = IFLOOR(U); \
I1 = I0 + 1; \
if (I0 < 0) \
else \
I = IFLOOR(u * SIZE); \
} \
+ else if (wrapMode == GL_MIRROR_CLAMP_ATI) { \
+ /* s limited to [0,1] */ \
+ /* i limited to [0,size-1] */ \
+ const GLfloat u = (GLfloat) fabs(S); \
+ if (u <= 0.0F) \
+ I = 0; \
+ else if (u >= 1.0F) \
+ I = SIZE - 1; \
+ else \
+ I = IFLOOR(u * SIZE); \
+ } \
+ else if (wrapMode == GL_MIRROR_CLAMP_TO_EDGE_ATI) { \
+ /* s limited to [min,max] */ \
+ /* i limited to [0, size-1] */ \
+ const GLfloat min = 1.0F / (2.0F * SIZE); \
+ const GLfloat max = 1.0F - min; \
+ const GLfloat u = (GLfloat) fabs(S); \
+ if (u < min) \
+ I = 0; \
+ else if (u > max) \
+ I = SIZE - 1; \
+ else \
+ I = IFLOOR(u * SIZE); \
+ } \
else { \
ASSERT(wrapMode == GL_CLAMP); \
/* s limited to [0,1] */ \
if (i < 0 || i >= (GLint) img->Width) {
/* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
- COPY_CHAN4(rgba, tObj->BorderColor);
+ COPY_CHAN4(rgba, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i, 0, 0, (GLvoid *) rgba);
GLchan t0[4], t1[4]; /* texels */
if (useBorderColor & I0BIT) {
- COPY_CHAN4(t0, tObj->BorderColor);
+ COPY_CHAN4(t0, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, 0, 0, (GLvoid *) t0);
}
}
if (useBorderColor & I1BIT) {
- COPY_CHAN4(t1, tObj->BorderColor);
+ COPY_CHAN4(t1, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, 0, 0, (GLvoid *) t1);
if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
/* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
- COPY_CHAN4(rgba, tObj->BorderColor);
+ COPY_CHAN4(rgba, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i, j, 0, (GLvoid *) rgba);
GLchan t11[4];
if (useBorderColor & (I0BIT | J0BIT)) {
- COPY_CHAN4(t00, tObj->BorderColor);
+ COPY_CHAN4(t00, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j0, 0, (GLvoid *) t00);
}
}
if (useBorderColor & (I1BIT | J0BIT)) {
- COPY_CHAN4(t10, tObj->BorderColor);
+ COPY_CHAN4(t10, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j0, 0, (GLvoid *) t10);
}
}
if (useBorderColor & (I0BIT | J1BIT)) {
- COPY_CHAN4(t01, tObj->BorderColor);
+ COPY_CHAN4(t01, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j1, 0, (GLvoid *) t01);
}
}
if (useBorderColor & (I1BIT | J1BIT)) {
- COPY_CHAN4(t11, tObj->BorderColor);
+ COPY_CHAN4(t11, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j1, 0, (GLvoid *) t11);
* Optimized 2-D texture sampling:
* S and T wrap mode == GL_REPEAT
* GL_NEAREST min/mag filter
- * No border
+ * No border,
+ * RowStride == Width,
* Format = GL_RGB
*/
static void
* S and T wrap mode == GL_REPEAT
* GL_NEAREST min/mag filter
* No border
+ * RowStride == Width,
* Format = GL_RGBA
*/
static void
const GLboolean repeatNoBorder = (tObj->WrapS == GL_REPEAT)
&& (tObj->WrapT == GL_REPEAT)
- && (tImg->Border == 0)
+ && (tImg->Border == 0 && (tImg->Width == tImg->RowStride))
&& (tImg->Format != GL_COLOR_INDEX);
ASSERT(lambda != NULL);
j < 0 || j >= (GLint) img->Height ||
k < 0 || k >= (GLint) img->Depth) {
/* Need this test for GL_CLAMP_TO_BORDER_ARB mode */
- COPY_CHAN4(rgba, tObj->BorderColor);
+ COPY_CHAN4(rgba, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i, j, k, (GLvoid *) rgba);
GLchan t100[4], t110[4], t101[4], t111[4];
if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
- COPY_CHAN4(t000, tObj->BorderColor);
+ COPY_CHAN4(t000, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j0, k0, (GLvoid *) t000);
}
}
if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
- COPY_CHAN4(t100, tObj->BorderColor);
+ COPY_CHAN4(t100, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j0, k0, (GLvoid *) t100);
}
}
if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
- COPY_CHAN4(t010, tObj->BorderColor);
+ COPY_CHAN4(t010, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j1, k0, (GLvoid *) t010);
}
}
if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
- COPY_CHAN4(t110, tObj->BorderColor);
+ COPY_CHAN4(t110, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j1, k0, (GLvoid *) t110);
}
if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
- COPY_CHAN4(t001, tObj->BorderColor);
+ COPY_CHAN4(t001, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j0, k1, (GLvoid *) t001);
}
}
if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
- COPY_CHAN4(t101, tObj->BorderColor);
+ COPY_CHAN4(t101, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j0, k1, (GLvoid *) t101);
}
}
if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
- COPY_CHAN4(t011, tObj->BorderColor);
+ COPY_CHAN4(t011, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i0, j1, k1, (GLvoid *) t011);
}
}
if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
- COPY_CHAN4(t111, tObj->BorderColor);
+ COPY_CHAN4(t111, tObj->_BorderChan);
}
else {
(*img->FetchTexel)(img, i1, j1, k1, (GLvoid *) t111);
}
+/**********************************************************************/
+/* Texture Rectangle Sampling Functions */
+/**********************************************************************/
+
+static void
+sample_nearest_rect(GLcontext *ctx, GLuint texUnit,
+ const struct gl_texture_object *tObj, GLuint n,
+ GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ const struct gl_texture_image *img = tObj->Image[0];
+ const GLfloat width = (GLfloat) img->Width;
+ const GLfloat height = (GLfloat) img->Height;
+ const GLint width_minus_1 = img->Width - 1;
+ const GLint height_minus_1 = img->Height - 1;
+ GLuint i;
+
+ (void) texUnit;
+ (void) lambda;
+
+ ASSERT(tObj->WrapS == GL_CLAMP ||
+ tObj->WrapS == GL_CLAMP_TO_EDGE ||
+ tObj->WrapS == GL_CLAMP_TO_BORDER_ARB);
+ ASSERT(tObj->WrapT == GL_CLAMP ||
+ tObj->WrapT == GL_CLAMP_TO_EDGE ||
+ tObj->WrapT == GL_CLAMP_TO_BORDER_ARB);
+ ASSERT(img->Format != GL_COLOR_INDEX);
+
+ /* XXX move Wrap mode tests outside of loops for common cases */
+ for (i = 0; i < n; i++) {
+ GLint row, col;
+ /* NOTE: we DO NOT use [0, 1] texture coordinates! */
+ if (tObj->WrapS == GL_CLAMP) {
+ col = IFLOOR( CLAMP(texcoords[i][0], 0.0F, width) );
+ }
+ else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
+ col = IFLOOR( CLAMP(texcoords[i][0], 0.5F, width - 0.5F) );
+ }
+ else {
+ col = IFLOOR( CLAMP(texcoords[i][0], -0.5F, width + 0.5F) );
+ }
+ if (tObj->WrapT == GL_CLAMP) {
+ row = IFLOOR( CLAMP(texcoords[i][1], 0.0F, height) );
+ }
+ else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
+ row = IFLOOR( CLAMP(texcoords[i][1], 0.5F, height - 0.5F) );
+ }
+ else {
+ row = IFLOOR( CLAMP(texcoords[i][1], -0.5F, height + 0.5F) );
+ }
+
+ col = CLAMP(col, 0, width_minus_1);
+ row = CLAMP(row, 0, height_minus_1);
+
+ (*img->FetchTexel)(img, col, row, 0, (GLvoid *) rgba[i]);
+ }
+}
+
+
+static void
+sample_linear_rect(GLcontext *ctx, GLuint texUnit,
+ const struct gl_texture_object *tObj, GLuint n,
+ GLfloat texcoords[][4],
+ const GLfloat lambda[], GLchan rgba[][4])
+{
+ const struct gl_texture_image *img = tObj->Image[0];
+ const GLfloat width = (GLfloat) img->Width;
+ const GLfloat height = (GLfloat) img->Height;
+ const GLint width_minus_1 = img->Width - 1;
+ const GLint height_minus_1 = img->Height - 1;
+ GLuint i;
+
+ (void) texUnit;
+ (void) lambda;
+
+ ASSERT(tObj->WrapS == GL_CLAMP ||
+ tObj->WrapS == GL_CLAMP_TO_EDGE ||
+ tObj->WrapS == GL_CLAMP_TO_BORDER_ARB);
+ ASSERT(tObj->WrapT == GL_CLAMP ||
+ tObj->WrapT == GL_CLAMP_TO_EDGE ||
+ tObj->WrapT == GL_CLAMP_TO_BORDER_ARB);
+ ASSERT(img->Format != GL_COLOR_INDEX);
+
+ /* XXX lots of opportunity for optimization in this loop */
+ for (i = 0; i < n; i++) {
+ GLfloat frow, fcol;
+ GLint row0, col0, row1, col1;
+ GLchan t00[4], t01[4], t10[4], t11[4];
+ GLfloat a, b, w00, w01, w10, w11;
+
+ /* NOTE: we DO NOT use [0, 1] texture coordinates! */
+ if (tObj->WrapS == GL_CLAMP) {
+ fcol = CLAMP(texcoords[i][0], 0.0F, width);
+ }
+ else if (tObj->WrapS == GL_CLAMP_TO_EDGE) {
+ fcol = CLAMP(texcoords[i][0], 0.5F, width - 0.5F);
+ }
+ else {
+ fcol = CLAMP(texcoords[i][0], -0.5F, width + 0.5F);
+ }
+ if (tObj->WrapT == GL_CLAMP) {
+ frow = CLAMP(texcoords[i][1], 0.0F, height);
+ }
+ else if (tObj->WrapT == GL_CLAMP_TO_EDGE) {
+ frow = CLAMP(texcoords[i][1], 0.5F, height - 0.5F);
+ }
+ else {
+ frow = CLAMP(texcoords[i][1], -0.5F, height + 0.5F);
+ }
+
+ /* compute integer rows/columns */
+ col0 = IFLOOR(fcol);
+ col1 = col0 + 1;
+ col0 = CLAMP(col0, 0, width_minus_1);
+ col1 = CLAMP(col1, 0, width_minus_1);
+ row0 = IFLOOR(frow);
+ row1 = row0 + 1;
+ row0 = CLAMP(row0, 0, height_minus_1);
+ row1 = CLAMP(row1, 0, height_minus_1);
+
+ /* get four texel samples */
+ (*img->FetchTexel)(img, col0, row0, 0, (GLvoid *) t00);
+ (*img->FetchTexel)(img, col1, row0, 0, (GLvoid *) t10);
+ (*img->FetchTexel)(img, col0, row1, 0, (GLvoid *) t01);
+ (*img->FetchTexel)(img, col1, row1, 0, (GLvoid *) t11);
+
+ /* compute sample weights */
+ a = FRAC(fcol);
+ b = FRAC(frow);
+ w00 = (1.0F-a) * (1.0F-b);
+ w10 = a * (1.0F-b);
+ w01 = (1.0F-a) * b ;
+ w11 = a * b ;
+
+ /* compute weighted average of samples */
+ rgba[i][0] =
+ (GLchan) (w00 * t00[0] + w10 * t10[0] + w01 * t01[0] + w11 * t11[0]);
+ rgba[i][1] =
+ (GLchan) (w00 * t00[1] + w10 * t10[1] + w01 * t01[1] + w11 * t11[1]);
+ rgba[i][2] =
+ (GLchan) (w00 * t00[2] + w10 * t10[2] + w01 * t01[2] + w11 * t11[2]);
+ rgba[i][3] =
+ (GLchan) (w00 * t00[3] + w10 * t10[3] + w01 * t01[3] + w11 * t11[3]);
+ }
+}
+
+
+static void
+sample_lambda_rect( GLcontext *ctx, GLuint texUnit,
+ const struct gl_texture_object *tObj, GLuint n,
+ GLfloat texcoords[][4], const GLfloat lambda[],
+ GLchan rgba[][4])
+{
+ GLuint minStart, minEnd, magStart, magEnd;
+
+ /* We only need lambda to decide between minification and magnification.
+ * There is no mipmapping with rectangular textures.
+ */
+ compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
+ n, lambda, &minStart, &minEnd, &magStart, &magEnd);
+
+ if (minStart < minEnd) {
+ if (tObj->MinFilter == GL_NEAREST) {
+ sample_nearest_rect( ctx, texUnit, tObj, minEnd - minStart,
+ texcoords + minStart, NULL, rgba + minStart);
+ }
+ else {
+ sample_linear_rect( ctx, texUnit, tObj, minEnd - minStart,
+ texcoords + minStart, NULL, rgba + minStart);
+ }
+ }
+ if (magStart < magEnd) {
+ if (tObj->MagFilter == GL_NEAREST) {
+ sample_nearest_rect( ctx, texUnit, tObj, magEnd - magStart,
+ texcoords + magStart, NULL, rgba + magStart);
+ }
+ else {
+ sample_linear_rect( ctx, texUnit, tObj, magEnd - magStart,
+ texcoords + magStart, NULL, rgba + magStart);
+ }
+ }
+}
+
+
+
/*
* Sample a shadow/depth texture.
*/
const struct gl_texture_image *texImage = tObj->Image[baseLevel];
const GLuint width = texImage->Width;
const GLuint height = texImage->Height;
- const GLchan ambient = tObj->ShadowAmbient;
+ GLchan ambient;
GLenum function;
GLchan result;
(void) unit;
ASSERT(tObj->Image[tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
- ASSERT(tObj->Dimensions == 1 || tObj->Dimensions == 2);
+ ASSERT(tObj->Target == GL_TEXTURE_1D ||
+ tObj->Target == GL_TEXTURE_2D ||
+ tObj->Target == GL_TEXTURE_RECTANGLE_NV);
+
+ UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
/* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
for (i = 0; i < n; i++) {
GLfloat depthSample;
GLint col, row;
+ /* XXX fix for texture rectangle! */
COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
depthSample = *((const GLfloat *) texImage->Data + row * width + col);
GLfloat u, v;
GLuint useBorderTexel;
+ /* XXX fix for texture rectangle! */
COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
result = 0;
break;
case GL_NEVER:
- result = CHAN_MAXF;
+ result = CHAN_MAX;
break;
case GL_NONE:
/* ordinary bilinear filtering */
const struct gl_texture_image *texImage = texObj->Image[baseLevel];
const GLuint width = texImage->Width;
const GLuint height = texImage->Height;
- const GLchan ambient = texObj->ShadowAmbient;
+ GLchan ambient;
GLboolean lequal, gequal;
- if (texObj->Dimensions != 2) {
+ if (texObj->Target != GL_TEXTURE_2D) {
_mesa_problem(ctx, "only 2-D depth textures supported at this time");
return;
}
return;
}
+ UNCLAMPED_FLOAT_TO_CHAN(ambient, tObj->ShadowAmbient);
+
if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
lequal = GL_TRUE;
gequal = GL_FALSE;
#endif
+/**
+ * We use this function when a texture object is in an "incomplete" state.
+ */
static void
null_sample_func( GLcontext *ctx, GLuint texUnit,
const struct gl_texture_object *tObj, GLuint n,
-/**********************************************************************/
-/* Texture Sampling Setup */
-/**********************************************************************/
-
-
-/*
+/**
* Setup the texture sampling function for this texture object.
*/
void
}
}
- switch (t->Dimensions) {
- case 1:
+ switch (t->Target) {
+ case GL_TEXTURE_1D:
if (format == GL_DEPTH_COMPONENT) {
swrast->TextureSample[texUnit] = sample_depth_texture;
}
swrast->TextureSample[texUnit] = sample_nearest_1d;
}
break;
- case 2:
+ case GL_TEXTURE_2D:
if (format == GL_DEPTH_COMPONENT) {
swrast->TextureSample[texUnit] = sample_depth_texture;
}
swrast->TextureSample[texUnit] = sample_nearest_2d;
}
break;
- case 3:
+ case GL_TEXTURE_3D:
if (needLambda) {
swrast->TextureSample[texUnit] = sample_lambda_3d;
}
swrast->TextureSample[texUnit] = sample_nearest_3d;
}
break;
- case 6: /* cube map */
+ case GL_TEXTURE_CUBE_MAP_ARB:
if (needLambda) {
swrast->TextureSample[texUnit] = sample_lambda_cube;
}
swrast->TextureSample[texUnit] = sample_nearest_cube;
}
break;
+ case GL_TEXTURE_RECTANGLE_NV:
+ if (needLambda) {
+ swrast->TextureSample[texUnit] = sample_lambda_rect;
+ }
+ else if (t->MinFilter == GL_LINEAR) {
+ swrast->TextureSample[texUnit] = sample_linear_rect;
+ }
+ else {
+ ASSERT(t->MinFilter == GL_NEAREST);
+ swrast->TextureSample[texUnit] = sample_nearest_rect;
+ }
+ break;
default:
- _mesa_problem(ctx, "invalid dimensions in _swrast_choose_texture_sample_func");
+ _mesa_problem(ctx, "invalid target in _swrast_choose_texture_sample_func");
}
}
}
#define PROD(A,B) ( (GLuint)(A) * ((GLuint)(B)+1) )
#define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
+
+/**
+ * Do texture application for GL_ARB/EXT_texture_env_combine.
+ * Input:
+ * ctx - rendering context
+ * textureUnit - the texture unit to apply
+ * n - number of fragments to process (span width)
+ * primary_rgba - incoming fragment color array
+ * texelBuffer - pointer to texel colors for all texture units
+ * Input/Output:
+ * rgba - incoming colors, which get modified here
+ */
static INLINE void
-texture_combine(const GLcontext *ctx,
- const struct gl_texture_unit *textureUnit,
- GLuint n,
- CONST GLchan (*primary_rgba)[4],
- CONST GLchan (*texel)[4],
- GLchan (*rgba)[4])
+texture_combine( const GLcontext *ctx, GLuint unit, GLuint n,
+ CONST GLchan (*primary_rgba)[4],
+ CONST GLchan *texelBuffer,
+ GLchan (*rgba)[4] )
{
+ const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
const GLchan (*argRGB [3])[4];
const GLchan (*argA [3])[4];
- GLuint i, j;
const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
const GLuint Ashift = textureUnit->CombineScaleShiftA;
#if CHAN_TYPE == GL_FLOAT
#else
const GLint half = (CHAN_MAX + 1) / 2;
#endif
+ GLuint i, j;
+ /* GLchan ccolor[3][4]; */
DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4); /* mac 32k limitation */
CHECKARRAY(ccolor, return); /* mac 32k limitation */
ASSERT(ctx->Extensions.EXT_texture_env_combine ||
ctx->Extensions.ARB_texture_env_combine);
+ ASSERT(SWRAST_CONTEXT(ctx)->_AnyTextureCombine);
+
/*
printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
* Do operand setup for up to 3 operands. Loop over the terms.
*/
for (j = 0; j < 3; j++) {
- switch (textureUnit->CombineSourceA[j]) {
+ const GLenum srcA = textureUnit->CombineSourceA[j];
+ const GLenum srcRGB = textureUnit->CombineSourceRGB[j];
+
+ switch (srcA) {
case GL_TEXTURE:
- argA[j] = texel;
+ argA[j] = (const GLchan (*)[4])
+ (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
break;
case GL_PRIMARY_COLOR_EXT:
argA[j] = primary_rgba;
}
break;
default:
- _mesa_problem(ctx, "invalid combine source");
+ /* ARB_texture_env_crossbar source */
+ {
+ const GLuint srcUnit = srcA - GL_TEXTURE0_ARB;
+ ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
+ if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
+ return;
+ argA[j] = (const GLchan (*)[4])
+ (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
+ }
}
- switch (textureUnit->CombineSourceRGB[j]) {
+ switch (srcRGB) {
case GL_TEXTURE:
- argRGB[j] = texel;
+ argRGB[j] = (const GLchan (*)[4])
+ (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
break;
case GL_PRIMARY_COLOR_EXT:
argRGB[j] = primary_rgba;
}
break;
default:
- _mesa_problem(ctx, "invalid combine source");
+ /* ARB_texture_env_crossbar source */
+ {
+ const GLuint srcUnit = srcRGB - GL_TEXTURE0_ARB;
+ ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
+ if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
+ return;
+ argRGB[j] = (const GLchan (*)[4])
+ (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
+ }
}
if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
}
}
break;
- case GL_DOT3_RGB_ARB:
- case GL_DOT3_RGBA_ARB:
+ case GL_DOT3_RGB_EXT:
+ case GL_DOT3_RGBA_EXT:
{
+ /* Do not scale the result by 1 2 or 4 */
const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
- /* ATI's EXT extension has a constant scale by 4. The ARB
- * one will likely remove this restriction, and we should
- * drop the EXT extension in favour of the ARB one.
- */
for (i = 0; i < n; i++) {
#if CHAN_TYPE == GL_FLOAT
GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
(arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
(arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
* 4.0F;
+ dot = CLAMP(dot, 0.0F, CHAN_MAXF);
#else
GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
(GLint)arg1[i][RCOMP] - half) +
(GLint)arg1[i][GCOMP] - half) +
S_PROD((GLint)arg0[i][BCOMP] - half,
(GLint)arg1[i][BCOMP] - half)) >> 6;
+ dot = CLAMP(dot, 0, CHAN_MAX);
#endif
+ rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
+ }
+ }
+ break;
+ case GL_DOT3_RGB_ARB:
+ case GL_DOT3_RGBA_ARB:
+ {
+ /* DO scale the result by 1 2 or 4 */
+ const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+ const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+ for (i = 0; i < n; i++) {
+#if CHAN_TYPE == GL_FLOAT
+ GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
+ (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
+ (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
+ * 4.0F * RGBmult;
+ dot = CLAMP(dot, 0.0, CHAN_MAXF);
+#else
+ GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
+ (GLint)arg1[i][RCOMP] - half) +
+ S_PROD((GLint)arg0[i][GCOMP] - half,
+ (GLint)arg1[i][GCOMP] - half) +
+ S_PROD((GLint)arg0[i][BCOMP] - half,
+ (GLint)arg1[i][BCOMP] - half)) >> 6;
+ dot <<= RGBshift;
dot = CLAMP(dot, 0, CHAN_MAX);
+#endif
rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
}
}
_mesa_problem(ctx, "invalid combine mode");
}
- /* Fix the alpha component for GL_DOT3_RGBA_EXT combining.
+ /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
+ * This is kind of a kludge. It would have been better if the spec
+ * were written such that the GL_COMBINE_ALPHA value could be set to
+ * GL_DOT3.
*/
if (textureUnit->CombineModeRGB == GL_DOT3_RGBA_EXT ||
textureUnit->CombineModeRGB == GL_DOT3_RGBA_ARB) {
#undef PROD
+/**
+ * Implement NVIDIA's GL_NV_texture_env_combine4 extension when
+ * texUnit->EnvMode == GL_COMBINE4_NV.
+ */
+static INLINE void
+texture_combine4( const GLcontext *ctx, GLuint unit, GLuint n,
+ CONST GLchan (*primary_rgba)[4],
+ CONST GLchan *texelBuffer,
+ GLchan (*rgba)[4] )
+{
+}
-/**********************************************************************/
-/* Texture Application */
-/**********************************************************************/
-/*
- * Combine incoming fragment color with texel color to produce output color.
+/**
+ * Apply a conventional OpenGL texture env mode (REPLACE, ADD, BLEND,
+ * MODULATE, or DECAL) to an array of fragments.
* Input: textureUnit - pointer to texture unit to apply
* format - base internal texture format
* n - number of fragments
* according to the texture environment mode.
*/
static void
-apply_texture( const GLcontext *ctx,
+texture_apply( const GLcontext *ctx,
const struct gl_texture_unit *texUnit,
GLuint n,
CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
format = texUnit->_Current->Image[baseLevel]->Format;
- if (format == GL_COLOR_INDEX || format == GL_DEPTH_COMPONENT) {
+ if (format == GL_COLOR_INDEX || format == GL_DEPTH_COMPONENT
+ || format == GL_YCBCR_MESA) {
format = GL_RGBA; /* a bit of a hack */
}
}
break;
default:
- _mesa_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
+ _mesa_problem(ctx, "Bad format (GL_REPLACE) in texture_apply");
return;
}
break;
}
break;
default:
- _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
+ _mesa_problem(ctx, "Bad format (GL_MODULATE) in texture_apply");
return;
}
break;
}
break;
default:
- _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
+ _mesa_problem(ctx, "Bad format (GL_DECAL) in texture_apply");
return;
}
break;
}
break;
default:
- _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
+ _mesa_problem(ctx, "Bad format (GL_BLEND) in texture_apply");
return;
}
break;
}
break;
default:
- _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
+ _mesa_problem(ctx, "Bad format (GL_ADD) in texture_apply");
return;
}
break;
- case GL_COMBINE_EXT:
- texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
- break;
-
default:
- _mesa_problem(ctx, "Bad env mode in apply_texture");
+ _mesa_problem(ctx, "Bad env mode in texture_apply");
return;
}
}
-/*
- * Apply a unit of texture mapping to the incoming fragments.
+/**
+ * Apply texture mapping to a span of fragments.
*/
void
-_swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
- GLfloat texcoords[][4], GLfloat lambda[],
- CONST GLchan primary_rgba[][4],
- GLchan rgba[][4] )
+_swrast_texture_span( GLcontext *ctx, struct sw_span *span )
{
- 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) { /* XXX need this? */
- const struct gl_texture_object *curObj = textureUnit->_Current;
- GLchan texel[MAX_WIDTH][4];
-
- if (lambda) {
-#if 0
- float min, max;
- int i;
- min = max = lambda[0];
- for (i = 1; i < n; i++) {
- if (lambda[i] > max)
- max = lambda[i];
- if (lambda[i] < min)
- min = lambda[i];
- }
- printf("min/max %g / %g\n", min, max);
-#endif
- if (textureUnit->LodBias != 0.0F) {
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+ GLchan primary_rgba[MAX_WIDTH][4];
+ GLuint unit;
+
+ ASSERT(span->end < MAX_WIDTH);
+ ASSERT(span->arrayMask & SPAN_TEXTURE);
+
+ /*
+ * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
+ */
+ if (swrast->_AnyTextureCombine)
+ MEMCPY(primary_rgba, span->array->rgba, 4 * span->end * sizeof(GLchan));
+
+ /*
+ * Must do all texture sampling before combining in order to
+ * accomodate GL_ARB_texture_env_crossbar.
+ */
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ const struct gl_texture_object *curObj = texUnit->_Current;
+ GLfloat *lambda = span->array->lambda[unit];
+ GLchan (*texels)[4] = (GLchan (*)[4])
+ (swrast->TexelBuffer + unit * (span->end * 4 * sizeof(GLchan)));
+
+ /* adjust texture lod (lambda) */
+ if (span->arrayMask | SPAN_LAMBDA) {
+ if (texUnit->LodBias != 0.0F) {
/* apply LOD bias, but don't clamp yet */
GLuint i;
- for (i=0;i<n;i++) {
- lambda[i] += textureUnit->LodBias;
+ for (i = 0; i < span->end; i++) {
+ lambda[i] += texUnit->LodBias;
}
}
const GLfloat min = curObj->MinLod;
const GLfloat max = curObj->MaxLod;
GLuint i;
- for (i=0;i<n;i++) {
+ for (i = 0; i < span->end; i++) {
GLfloat l = lambda[i];
lambda[i] = CLAMP(l, min, max);
}
}
}
- /* Sample the texture for n fragments */
- SWRAST_CONTEXT(ctx)->TextureSample[texUnit]( ctx, texUnit,
- textureUnit->_Current,
- n, texcoords,
- lambda, texel );
-
- apply_texture( ctx, textureUnit, n, primary_rgba,
- (const GLchan (*)[4]) texel, rgba );
+ /* Sample the texture (span->end fragments) */
+ swrast->TextureSample[unit]( ctx, unit, texUnit->_Current,
+ span->end, span->array->texcoords[unit],
+ lambda, texels );
}
}
-}
-
-
-/*
- * Apply multiple texture stages (or just unit 0) to the span.
- * At some point in the future we'll probably modify this so that
- * texels from any texture unit are available in any combiner unit.
- * That'll require doing all the texture sampling first, and then
- * all the application (blending) afterward.
- */
-void
-_swrast_multitexture_fragments( GLcontext *ctx, struct sw_span *span )
-{
- if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) {
- /* multitexture */
- GLchan primary_rgba[MAX_WIDTH][4];
- GLuint unit;
- ASSERT(span->end < MAX_WIDTH);
-
- /* save copy of the span colors (the GL_PRIMARY_COLOR) */
- MEMCPY(primary_rgba, span->color.rgba, 4 * span->end * sizeof(GLchan));
-
- /* loop over texture units, modifying the span->color.rgba values */
- for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
- if (ctx->Texture.Unit[unit]._ReallyEnabled) {
- _swrast_texture_fragments( ctx, unit, span->end,
- span->texcoords[unit],
- (span->arrayMask & SPAN_LAMBDA) ?
- span->lambda[unit] : NULL,
- (CONST GLchan (*)[4]) primary_rgba,
- span->color.rgba );
+ /*
+ * OK, now apply the texture (aka texture combine/blend).
+ * We modify the span->color.rgba values.
+ */
+ for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+ if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ if (texUnit->EnvMode == GL_COMBINE_EXT) {
+ /* GL_ARB/EXT_texture_env_combine */
+ texture_combine( ctx, unit, span->end,
+ (CONST GLchan (*)[4]) primary_rgba,
+ swrast->TexelBuffer,
+ span->array->rgba );
+ }
+ else if (texUnit->EnvMode == GL_COMBINE4_NV) {
+ /* GL_NV_texture_env_combine4 */
+ texture_combine4( ctx, unit, span->end,
+ (CONST GLchan (*)[4]) primary_rgba,
+ swrast->TexelBuffer,
+ span->array->rgba );
+ }
+ else {
+ /* conventional texture blend */
+ const GLchan (*texels)[4] = (const GLchan (*)[4])
+ (swrast->TexelBuffer + unit *
+ (span->end * 4 * sizeof(GLchan)));
+ texture_apply( ctx, texUnit, span->end,
+ (CONST GLchan (*)[4]) primary_rgba, texels,
+ span->array->rgba );
}
}
}
- else {
- /* Just unit 0 enabled */
- ASSERT(ctx->Texture._ReallyEnabled & TEXTURE0_ANY);
-
- _swrast_texture_fragments( ctx, 0, span->end,
- span->texcoords[0],
- (span->arrayMask & SPAN_LAMBDA) ?
- span->lambda[0] : NULL,
- (CONST GLchan (*)[4]) span->color.rgba,
- span->color.rgba );
- }
}