st/code/renderer/tr_state-states-textures.c

833 lines
21 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2007 HermitWorks Entertainment Corporation
This file is part of the Space Trader source code.
The Space Trader source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
The Space Trader source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the Space Trader source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "tr_local.h"
#include "tr_state-local.h"
static samplerState_t defaultSampler2D;
static samplerState_t defaultSamplerRECT;
static struct
{
image_t *currTex[STATE_MAX_TEXTURE_UNITS];
samplerState_t samplers[STATE_MAX_TEXTURE_UNITS];
bool allowAniso;
GLenum currTmu;
GLenum currClTmu;
uint numTmus;
GLfloat maxAniso, defAniso;
int minLod;
} gls;
void R_StateSetActiveClientTmuUntracked( GLenum tmu )
{
if( gls.currClTmu == tmu )
return;
glClientActiveTextureARB( tmu );
gls.currClTmu = tmu;
}
void R_StateSetActiveTmuUntracked( GLenum tmu )
{
if( gls.currTmu == tmu )
return;
glActiveTextureARB( tmu );
gls.currTmu = tmu;
}
GLenum R_StateGetRectTarget( void )
{
if( GLEW_ARB_texture_rectangle )
return GL_TEXTURE_RECTANGLE_ARB;
else if( GLEW_EXT_texture_rectangle )
return GL_TEXTURE_RECTANGLE_EXT;
else if( GLEW_NV_texture_rectangle )
return GL_TEXTURE_RECTANGLE_NV;
else
return 0;
}
qboolean R_StateTargetIsRect( GLenum target )
{
switch( target )
{
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
case GL_TEXTURE_3D_EXT:
case GL_TEXTURE_CUBE_MAP_ARB:
return qfalse;
case GL_TEXTURE_RECTANGLE_ARB:
//case GL_TEXTURE_RECTANGLE_EXT: ( == GL_TEXTURE_RECTANGLE_ARB )
//case GL_TEXTURE_RECTANGLE_NV: ( == GL_TEXTURE_RECTANGLE_ARB )
return qtrue;
}
return qfalse;
}
static void R_StateSetTextureMinLodInternal( GLenum target, GLint minLod, GLenum tmu )
{
GLint w, h;
uint m, n;
/*
Yes, I'm calling it Lod. Yes, this should use GL_TEXTURE_MIN_LOD.
But ATI hardware sucks at GL_TEXTURE_MIN_LOD. Turning it on for
even one texture literally forces the application into software
mode. So instead we invite do an almost equivalent thing with the
GL_TEXTURE_BASE_LEVEL parameter.
*/
if( !GLEW_VERSION_1_2 && !GLEW_SGIS_texture_lod )
return;
R_StateSetActiveTmuUntracked( tmu );
if( R_StateTargetIsRect( target ) )
//no mips to control
return;
glGetTexLevelParameteriv( target, 0, GL_TEXTURE_WIDTH, &w );
glGetTexLevelParameteriv( target, 0, GL_TEXTURE_HEIGHT, &h );
if( w < 0 || h < 0 )
//what happened here?
return;
m = (w > h) ? w : h;
//get the log2 of the max dimension
n = 0;
while( m >> n )
n++;
n--;
//see if there actually is a mip level beyond the base level
glGetTexLevelParameteriv( target, 1, GL_TEXTURE_WIDTH, &w );
if( !w )
return;
//clamp the Lod value
if( minLod > (int)n )
minLod = n;
if( minLod < 0 )
minLod = 0;
glTexParameteri( target, GL_TEXTURE_BASE_LEVEL_SGIS, minLod );
}
static void R_StateSetTextureSamplerInternal( samplerState_t t, GLenum tmu )
{
bool isRect;
const samplerState_t *d;
uint idx = tmu - GL_TEXTURE0_ARB;
image_t *img = gls.currTex[idx];
gls.samplers[idx] = t;
if( !img )
return;
R_StateSetActiveTmuUntracked( tmu );
isRect = R_StateTargetIsRect( img->texTarget );
d = isRect ? &defaultSamplerRECT : &defaultSampler2D;
if( !t.minFilter ) t.minFilter = d->minFilter;
if( !t.magFilter ) t.magFilter = d->magFilter;
if( !t.wrapS ) t.wrapS = d->wrapS;
if( !t.wrapT ) t.wrapT = d->wrapT;
if( !t.wrapR ) t.wrapR = d->wrapR;
if( !t.maxAniso ) t.maxAniso = d->maxAniso;
if( !img->mipmap || isRect )
{
switch( t.minFilter )
{
case GL_LINEAR_MIPMAP_LINEAR:
case GL_LINEAR_MIPMAP_NEAREST:
t.minFilter = GL_LINEAR;
break;
case GL_NEAREST_MIPMAP_LINEAR:
case GL_NEAREST_MIPMAP_NEAREST:
t.minFilter = GL_NEAREST;
break;
}
}
if( isRect )
{
//impose remaining textureRECT limits
switch( t.wrapS )
{
case GL_REPEAT:
t.wrapS = GL_CLAMP_TO_EDGE_EXT;
break;
}
switch( t.wrapT )
{
case GL_REPEAT:
t.wrapT = GL_CLAMP_TO_EDGE_EXT;
break;
}
}
//update the filter
if( img->samplerState.minFilter != t.minFilter )
{
glTexParameteri( img->texTarget, GL_TEXTURE_MIN_FILTER, t.minFilter );
img->samplerState.minFilter = t.minFilter;
}
if( img->samplerState.magFilter != t.magFilter )
{
glTexParameteri( img->texTarget, GL_TEXTURE_MAG_FILTER, t.magFilter );
img->samplerState.magFilter = t.magFilter;
}
//update the address mode
switch( img->texTarget )
{
case GL_TEXTURE_3D_EXT:
if( t.wrapR != img->samplerState.wrapR )
{
glTexParameteri( img->texTarget, GL_TEXTURE_WRAP_R_EXT, t.wrapR );
img->samplerState.wrapR = t.wrapR;
}
//fallthrough is intended
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE_ARB:
//case GL_TEXTURE_RECTANGLE_EXT: ( == GL_TEXTURE_RECTANGLE_ARB )
//case GL_TEXTURE_RECTANGLE_NV: ( == GL_TEXTURE_RECTANGLE_ARB )
case GL_TEXTURE_CUBE_MAP_ARB:
if( t.wrapT != img->samplerState.wrapT )
{
glTexParameteri( img->texTarget, GL_TEXTURE_WRAP_T, t.wrapT );
img->samplerState.wrapT = t.wrapT;
}
//fallthrough is intended
case GL_TEXTURE_1D:
if( t.wrapS != img->samplerState.wrapS )
{
glTexParameteri( img->texTarget, GL_TEXTURE_WRAP_S, t.wrapS );
img->samplerState.wrapS = t.wrapS;
}
break;
}
if( img->mipmap && gls.allowAniso )
{
if( t.maxAniso != img->samplerState.maxAniso )
{
glTexParameterf( img->texTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, t.maxAniso );
img->samplerState.maxAniso = t.maxAniso;
}
}
}
static void R_StateResetTextureSamplerInternal( GLenum tmu )
{
const image_t *img = gls.currTex[tmu - GL_TEXTURE0_ARB];
qboolean isRect;
const samplerState_t *d;
if( !img )
return;
isRect = R_StateTargetIsRect( img->texTarget );
d = isRect ? &defaultSamplerRECT : &defaultSampler2D;
R_StateSetTextureSamplerInternal( *d, tmu );
}
void R_StateSetDefaultTextureModesUntracked( GLenum target, qboolean mipmap, GLenum tmu )
{
bool isRect = R_StateTargetIsRect( target );
const samplerState_t *d = isRect ? &defaultSamplerRECT : &defaultSampler2D;
GLenum minFilter = d->minFilter;
R_StateSetActiveTmuUntracked( tmu );
if( !mipmap )
{
switch( minFilter )
{
case GL_LINEAR_MIPMAP_NEAREST:
case GL_LINEAR_MIPMAP_LINEAR:
minFilter = GL_LINEAR;
break;
case GL_NEAREST_MIPMAP_NEAREST:
case GL_NEAREST_MIPMAP_LINEAR:
minFilter = GL_NEAREST;
break;
}
}
glTexParameteri( target, GL_TEXTURE_MIN_FILTER, minFilter );
glTexParameteri( target, GL_TEXTURE_MAG_FILTER, d->magFilter );
switch( target )
{
case GL_TEXTURE_3D_EXT:
glTexParameteri( target, GL_TEXTURE_WRAP_R_EXT, d->wrapR );
//fallthrough is intended
case GL_TEXTURE_2D:
case GL_TEXTURE_RECTANGLE_ARB:
//case GL_TEXTURE_RECTANGLE_EXT: ( == GL_TEXTURE_RECTANGLE_ARB )
//case GL_TEXTURE_RECTANGLE_NV: ( == GL_TEXTURE_RECTANGLE_ARB )
case GL_TEXTURE_CUBE_MAP_ARB:
glTexParameteri( target, GL_TEXTURE_WRAP_T, d->wrapT );
//fallthrough is intended
case GL_TEXTURE_1D:
glTexParameteri( target, GL_TEXTURE_WRAP_S, d->wrapS );
break;
}
R_StateSetTextureMinLodInternal( target, gls.minLod, tmu );
}
static void R_StateSetTextureInternal( image_t *image, GLenum tmu )
{
qboolean resetMatrix = qfalse;
uint idx = tmu - GL_TEXTURE0_ARB;
image_t **img = gls.currTex + idx;
R_StateSetActiveTmuUntracked( tmu );
if( !image && *img )
{
glBindTexture( (*img)->texTarget, 0 );
glDisable( (*img)->texTarget );
}
else
{
if( *img == image )
return;
if( *img )
{
if( (*img)->texTarget != image->texTarget )
{
glDisable( (*img)->texTarget );
glEnable( image->texTarget );
}
resetMatrix = (*img)->addrMode != image->addrMode ||
((*img)->addrMode == TAM_Dimensions && ((*img)->uploadWidth != image->uploadWidth ||
(*img)->uploadHeight != image->uploadHeight));
}
else
{
glEnable( image->texTarget );
resetMatrix = qtrue;
}
}
if( resetMatrix )
{
glMatrixMode( GL_TEXTURE );
glLoadIdentity();
if( image && image->addrMode == TAM_Dimensions )
glScalef( (float)image->uploadWidth, (float)image->uploadHeight, (float)image->uploadDepth );
R_StateCountIncrement( CSN_TexMat0 + idx );
}
if( image )
{
image->frameUsed = tr.frameCount;
if( !*img || (*img)->texnum != image->texnum )
{
glBindTexture( image->texTarget, image->texnum );
*img = image;
R_StateSetTextureSamplerInternal( gls.samplers[idx], tmu );
}
}
else
*img = NULL;
}
static void R_StateSetTextureInternalRaw( GLuint tex, GLenum target, qboolean mipmap, GLenum tmu )
{
static int dummyflip[STATE_MAX_TEXTURE_UNITS];
static image_t dummies[STATE_MAX_TEXTURE_UNITS][2];
int idx = tmu - GL_TEXTURE0_ARB;
image_t *di = dummies[idx] + dummyflip[idx];
Com_Memset( di, 0, sizeof( image_t ) );
di->addrMode = TAM_Normalized;
di->texTarget = target;
di->texnum = tex;
di->mipmap = mipmap;
dummyflip[idx] = 1 - dummyflip[idx];
R_StateSetTextureInternal( di, tmu );
}
static struct
{
const char *name;
GLenum min2D;
GLenum minRECT;
GLenum mag;
} modes[] =
{
{ "Nearest", GL_NEAREST, GL_NEAREST, GL_NEAREST },
{ "Linear", GL_LINEAR, GL_LINEAR, GL_LINEAR },
{ "NearestMipNearest", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST, GL_NEAREST },
{ "LinearMipNearest", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR, GL_LINEAR },
{ "NearestMipLinear", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, GL_NEAREST },
{ "LinearMipLinear", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_LINEAR },
{ "AnisoMipLinear", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_LINEAR },
};
void R_StateSetTextureModeCvar( const char *string )
{
int i;
for( i = 0; i < lengthof( modes ); i++ )
if ( Q_stricmp( modes[i].name, string ) == 0 )
break;
if( i == lengthof( modes ) )
{
ri.Printf (PRINT_ALL, "bad filter name\n");
return;
}
defaultSampler2D.magFilter = modes[i].mag;
defaultSampler2D.minFilter = modes[i].min2D;
defaultSamplerRECT.magFilter = modes[i].mag;
defaultSamplerRECT.minFilter = modes[i].minRECT;
//values apply as of next R_StateSetTexture or R_StateSetTextureSampler
}
void R_StateSetTextureAnisotropyCvar( int aniso )
{
if( aniso < 1 )
aniso = 1;
if( aniso > gls.maxAniso )
aniso = gls.maxAniso;
gls.defAniso = aniso;
defaultSampler2D.maxAniso = aniso;
//values apply as of next R_StateSetTexture or R_StateSetTextureSampler
}
void R_StateSetTextureMinLodCvar( int minLod )
{
int i;
if( minLod < 0 ) minLod = 0;
if( minLod > 1000 ) minLod = 1000;
gls.minLod = minLod;
//change all the existing texture objects
for( i = 0; i < tr.numImages; i++ )
{
image_t *glt = tr.images[ i ];
if( glt->mipmap )
{
R_StateSetTexture( glt, GL_TEXTURE0_ARB );
R_StateSetTextureMinLodInternal( glt->texTarget, minLod, GL_TEXTURE0_ARB );
}
}
}
/*
Setters and resetters go here.
*/
void R_StateSetTexture( image_t *image, GLenum tmu )
{
trackedStateName_t state = (trackedStateName_t)(TSN_Texture0 + (tmu - GL_TEXTURE0_ARB));
if( !image )
R_StateSetDefault( state );
else
{
R_StateSetTextureInternal( image, tmu );
R_StateChanged( state );
}
}
void R_StateSetTextureRaw( GLuint tex, GLenum target, qboolean mipmap, GLenum tmu )
{
trackedStateName_t state = (trackedStateName_t)(TSN_Texture0 + (tmu - GL_TEXTURE0_ARB));
if( !tex )
R_StateSetDefault( state );
else
{
R_StateSetTextureInternalRaw( tex, target, mipmap, tmu );
R_StateChanged( state );
}
}
static void R_StateResetTexture( trackedState_t *s )
{
R_StateSetTextureInternal( NULL, s->data.asglenum );
}
void R_StateSetTextureSampler( const samplerState_t *sampler, GLenum tmu )
{
R_StateSetTextureSamplerInternal( *sampler, tmu );
}
static void R_StateResetTextureSampler( trackedState_t *s )
{
R_StateResetTextureSamplerInternal( s->data.asglenum );
}
void R_StateSetTextureEnvMode( GLenum env, GLenum tmu )
{
trackedStateName_t state = (trackedStateName_t)(TSN_TexEnvMode0 + (tmu - GL_TEXTURE0_ARB));
switch( env )
{
case 0:
case GL_MODULATE:
R_StateSetDefault( state );
return;
case GL_REPLACE:
case GL_DECAL:
case GL_BLEND:
case GL_ADD:
R_StateSetActiveTmuUntracked( tmu );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, env );
break;
case GL_COMBINE_ARB:
ri.Error( ERR_DROP, "R_StateSetTextureEnvMode: cannot set GL_COMBINE_ARB through this function, use R_StateSetTextureEnvMode2\n" );
default:
ri.Error( ERR_DROP, "R_StateSetTextureEnvMode: invalid env '%d' passed\n", env );
break;
}
R_StateChanged( state );
}
void R_StateSetTextureEnvMode2( const textureEnv_t *env, GLenum tmu )
{
trackedStateName_t state = (trackedStateName_t)(TSN_TexEnvMode0 + (tmu - GL_TEXTURE0_ARB));
bool setColor;
if( !env->complex )
{
R_StateSetTextureEnvMode( env->color_mode, tmu );
return;
}
R_StateSetActiveTmuUntracked( tmu );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
setColor = false;
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, env->color_mode );
//set the first source
if( env->src[0].color_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, env->src[0].color_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, env->src[0].color_op );
if( env->color_mode != GL_REPLACE )
{
//set second color source
if( env->src[1].color_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, env->src[1].color_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, env->src[1].color_op );
if( env->color_mode == GL_INTERPOLATE_ARB )
{
//set the third color source
if( env->src[2].color_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, env->src[2].color_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, env->src[2].color_op );
}
}
if( env->color_mode != GL_DOT3_RGBA_ARB ) //alpha is irrelevant in this case
{
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, env->alpha_mode );
if( env->src[0].alpha_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, env->src[0].alpha_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, env->src[0].alpha_op );
if( env->alpha_mode != GL_REPLACE )
{
//set second alpha source
if( env->src[1].alpha_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, env->src[1].alpha_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, env->src[1].alpha_op );
if( env->alpha_mode == GL_INTERPOLATE_ARB )
{
if( env->src[2].alpha_src == GL_CONSTANT_ARB )
setColor = true;
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_ALPHA_ARB, env->src[2].alpha_src );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_ALPHA_ARB, env->src[2].alpha_op );
}
}
}
glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, env->color_scale );
glTexEnvf( GL_TEXTURE_ENV, GL_ALPHA_SCALE, env->alpha_scale );
#undef resolve_def
if( setColor )
glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, env->color );
R_StateChanged( state );
}
static void R_StateResetTextureEnvMode( trackedState_t *s )
{
R_StateSetActiveTmuUntracked( s->data.asglenum );
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
}
void R_StateResolveTextureEnv( textureEnv_t *env )
{
env->complex = false;
#define resolve_def( v, d ) { if( !env->v ) env->v = d; if( env->v != d ) env->complex = true; }
resolve_def( color_mode, GL_MODULATE );
resolve_def( alpha_mode, GL_MODULATE );
resolve_def( src[0].color_src, GL_TEXTURE );
resolve_def( src[0].color_op, GL_SRC_COLOR );
resolve_def( src[0].alpha_src, GL_TEXTURE );
resolve_def( src[0].alpha_op, GL_SRC_ALPHA );
resolve_def( src[1].color_src, GL_PREVIOUS_ARB );
resolve_def( src[1].color_op, GL_SRC_COLOR );
resolve_def( src[1].alpha_src, GL_PREVIOUS_ARB );
resolve_def( src[1].alpha_op, GL_SRC_ALPHA );
resolve_def( src[2].color_src, GL_CONSTANT_ARB );
resolve_def( src[2].color_op, GL_SRC_ALPHA );
resolve_def( src[2].alpha_src, GL_CONSTANT_ARB );
resolve_def( src[2].alpha_op, GL_SRC_ALPHA );
resolve_def( color_scale, 1.0F );
resolve_def( alpha_scale, 1.0F );
#undef resolve_def
}
void R_StateSetTextureMatrixCountedRaw( const float *mat, GLenum tmu )
{
uint idx = tmu - GL_TEXTURE0_ARB;
R_StateSetActiveTmuUntracked( tmu );
glMatrixMode( GL_TEXTURE );
glLoadMatrixf( mat );
R_StateCountIncrement( CSN_TexMat0 + idx );
}
void R_StateSetTextureMatrixCountedAffine( const affine_t *mat, GLenum tmu )
{
float m[16];
uint idx = tmu - GL_TEXTURE0_ARB;
Matrix_SetFromAffine( m, mat );
R_StateSetActiveTmuUntracked( tmu );
glMatrixMode( GL_TEXTURE );
glLoadMatrixf( m );
R_StateCountIncrement( CSN_TexMat0 + idx );
}
void R_StateMulTextureMatrixCountedRaw( const float *mat, GLenum tmu )
{
uint idx = tmu - GL_TEXTURE0_ARB;
R_StateSetActiveTmuUntracked( tmu );
glMatrixMode( GL_TEXTURE );
glMultMatrixf( mat );
R_StateCountIncrement( CSN_TexMat0 + idx );
}
void R_StateMulTextureMatrixCountedAffine( const affine_t *mat, GLenum tmu )
{
float m[16];
uint idx = tmu - GL_TEXTURE0_ARB;
Matrix_SetFromAffine( m, mat );
R_StateSetActiveTmuUntracked( tmu );
glMatrixMode( GL_TEXTURE );
glMultMatrixf( m );
R_StateCountIncrement( CSN_TexMat0 + idx );
}
uint R_StateGetNumTextureUnits( void )
{
return gls.numTmus;
}
void R_StateSetupTextureStates( void )
{
//init the bookkeeping data
memset( &gls, 0, sizeof( gls ) );
gls.currTmu = GL_TEXTURE0_ARB;
defaultSampler2D.minFilter = GL_LINEAR_MIPMAP_LINEAR;
defaultSampler2D.magFilter = GL_LINEAR;
defaultSampler2D.wrapS = GL_REPEAT;
defaultSampler2D.wrapT = GL_REPEAT;
defaultSampler2D.wrapR = GL_REPEAT;
defaultSampler2D.maxAniso = 1;
defaultSamplerRECT.minFilter = GL_LINEAR;
defaultSamplerRECT.magFilter = GL_LINEAR;
defaultSamplerRECT.wrapS = GL_CLAMP_TO_EDGE_EXT;
defaultSamplerRECT.wrapT = GL_CLAMP_TO_EDGE_EXT;
defaultSamplerRECT.wrapR = GL_CLAMP_TO_EDGE_EXT;
defaultSamplerRECT.maxAniso = 1;
gls.allowAniso = false;
if( GLEW_EXT_texture_filter_anisotropic )
{
glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gls.maxAniso );
if( gls.maxAniso > 1 )
{
gls.allowAniso = true;
if( gls.maxAniso > 8 )
gls.defAniso = gls.maxAniso / 2;
else
gls.defAniso = gls.maxAniso;
}
}
gls.minLod = 0;
//set up the tracked states
{
uint i;
GLuint numTmus;
trackedState_t *s;
#define DefineTrackedState( _name, _reset ) \
{ \
s = track.s + (int)(_name); \
memset( s, 0, sizeof( *s ) ); \
s->name = (trackedStateName_t)(_name); \
s->reset = _reset; \
}
glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&numTmus );
if( numTmus > STATE_MAX_TEXTURE_UNITS )
numTmus = STATE_MAX_TEXTURE_UNITS;
gls.numTmus = numTmus;
#define DefineTrackedTextureStateI( _name, _reset ) \
{ \
DefineTrackedState( _name + i, _reset ); \
s->data.asglenum = GL_TEXTURE0_ARB + i; \
}
for( i = 0; i < numTmus; i++ )
{
DefineTrackedTextureStateI( TSN_Texture0, R_StateResetTexture );
DefineTrackedTextureStateI( TSN_TexSampler0, R_StateResetTextureSampler );
DefineTrackedTextureStateI( TSN_TexEnvMode0, R_StateResetTextureEnvMode );
}
for( i = numTmus; i < STATE_MAX_TEXTURE_UNITS; i++ )
{
DefineTrackedTextureStateI( TSN_Texture0, NULL );
DefineTrackedTextureStateI( TSN_TexSampler0, NULL );
DefineTrackedTextureStateI( TSN_TexEnvMode0, NULL );
}
#undef DefineTrackedTextureStateI
#undef DefineTrackedState_GLEnable
#undef DefineTrackedState_GLDisable
#undef DefineTrackedState
}
//set up the counted states
{
uint i;
countedState_t *s;
#define DefineCountedState( _name ) \
{ \
s = count.s + (int)(_name); \
memset( s, 0, sizeof( *s ) ); \
s->name = (_name); \
}
for( i = CSN_TextureFirstState; i <= CSN_TextureLastState; i++ )
DefineCountedState( i );
#undef DefineCountedState
}
}