2013-04-22 05:25:59 +00:00
// tr_shade.c
# include "tr_local.h"
2013-04-28 01:09:47 +00:00
# include "tr_quicksprite.h"
2013-04-22 05:25:59 +00:00
/*
THIS ENTIRE FILE IS BACK END
This file deals with applying shaders to surface data in the tess struct .
*/
shaderCommands_t tess ;
static qboolean setArraysOnce ;
color4ub_t styleColors [ MAX_LIGHT_STYLES ] ;
/*
= = = = = = = = = = = = = = = =
R_ArrayElementDiscrete
This is just for OpenGL conformance testing , it should never be the fastest
= = = = = = = = = = = = = = = =
*/
static void APIENTRY R_ArrayElementDiscrete ( GLint index ) {
qglColor4ubv ( tess . svars . colors [ index ] ) ;
if ( glState . currenttmu ) {
qglMultiTexCoord2fARB ( 0 , tess . svars . texcoords [ 0 ] [ index ] [ 0 ] , tess . svars . texcoords [ 0 ] [ index ] [ 1 ] ) ;
qglMultiTexCoord2fARB ( 1 , tess . svars . texcoords [ 1 ] [ index ] [ 0 ] , tess . svars . texcoords [ 1 ] [ index ] [ 1 ] ) ;
} else {
qglTexCoord2fv ( tess . svars . texcoords [ 0 ] [ index ] ) ;
}
qglVertex3fv ( tess . xyz [ index ] ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_DrawStripElements
= = = = = = = = = = = = = = = = = = =
*/
static int c_vertexes ; // for seeing how long our average strips are
static int c_begins ;
static void R_DrawStripElements ( int numIndexes , const glIndex_t * indexes , void ( APIENTRY * element ) ( GLint ) ) {
int i ;
int last [ 3 ] = { - 1 , - 1 , - 1 } ;
qboolean even ;
c_begins + + ;
if ( numIndexes < = 0 ) {
return ;
}
qglBegin ( GL_TRIANGLE_STRIP ) ;
// prime the strip
element ( indexes [ 0 ] ) ;
element ( indexes [ 1 ] ) ;
element ( indexes [ 2 ] ) ;
c_vertexes + = 3 ;
last [ 0 ] = indexes [ 0 ] ;
last [ 1 ] = indexes [ 1 ] ;
last [ 2 ] = indexes [ 2 ] ;
even = qfalse ;
for ( i = 3 ; i < numIndexes ; i + = 3 )
{
// odd numbered triangle in potential strip
if ( ! even )
{
// check previous triangle to see if we're continuing a strip
if ( ( indexes [ i + 0 ] = = last [ 2 ] ) & & ( indexes [ i + 1 ] = = last [ 1 ] ) )
{
element ( indexes [ i + 2 ] ) ;
c_vertexes + + ;
assert ( indexes [ i + 2 ] < tess . numVertexes ) ;
even = qtrue ;
}
// otherwise we're done with this strip so finish it and start
// a new one
else
{
qglEnd ( ) ;
qglBegin ( GL_TRIANGLE_STRIP ) ;
c_begins + + ;
element ( indexes [ i + 0 ] ) ;
element ( indexes [ i + 1 ] ) ;
element ( indexes [ i + 2 ] ) ;
c_vertexes + = 3 ;
even = qfalse ;
}
}
else
{
// check previous triangle to see if we're continuing a strip
if ( ( last [ 2 ] = = indexes [ i + 1 ] ) & & ( last [ 0 ] = = indexes [ i + 0 ] ) )
{
element ( indexes [ i + 2 ] ) ;
c_vertexes + + ;
even = qfalse ;
}
// otherwise we're done with this strip so finish it and start
// a new one
else
{
qglEnd ( ) ;
qglBegin ( GL_TRIANGLE_STRIP ) ;
c_begins + + ;
element ( indexes [ i + 0 ] ) ;
element ( indexes [ i + 1 ] ) ;
element ( indexes [ i + 2 ] ) ;
c_vertexes + = 3 ;
even = qfalse ;
}
}
// cache the last three vertices
last [ 0 ] = indexes [ i + 0 ] ;
last [ 1 ] = indexes [ i + 1 ] ;
last [ 2 ] = indexes [ i + 2 ] ;
}
qglEnd ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
R_DrawElements
Optionally performs our own glDrawElements that looks for strip conditions
instead of using the single glDrawElements call that may be inefficient
without compiled vertex arrays .
= = = = = = = = = = = = = = = = = =
*/
static void R_DrawElements ( int numIndexes , const glIndex_t * indexes ) {
int primitives ;
primitives = r_primitives - > integer ;
// default is to use triangles if compiled vertex arrays are present
if ( primitives = = 0 ) {
if ( qglLockArraysEXT ) {
primitives = 2 ;
} else {
primitives = 1 ;
}
}
if ( primitives = = 2 ) {
qglDrawElements ( GL_TRIANGLES ,
numIndexes ,
GL_INDEX_TYPE ,
indexes ) ;
return ;
}
if ( primitives = = 1 ) {
R_DrawStripElements ( numIndexes , indexes , qglArrayElement ) ;
return ;
}
if ( primitives = = 3 ) {
R_DrawStripElements ( numIndexes , indexes , R_ArrayElementDiscrete ) ;
return ;
}
// anything else will cause no drawing
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
SURFACE SHADERS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = =
R_BindAnimatedImage
= = = = = = = = = = = = = = = = =
*/
// de-static'd because tr_quicksprite wants it
void R_BindAnimatedImage ( textureBundle_t * bundle ) {
int index ;
if ( bundle - > isVideoMap ) {
ri . CIN_RunCinematic ( bundle - > videoMapHandle ) ;
ri . CIN_UploadCinematic ( bundle - > videoMapHandle ) ;
return ;
}
if ( ( r_fullbright - > value /*|| tr.refdef.doFullbright */ ) & & bundle - > isLightmap )
{
GL_Bind ( tr . whiteImage ) ;
return ;
}
if ( bundle - > numImageAnimations < = 1 ) {
GL_Bind ( bundle - > image [ 0 ] ) ;
return ;
}
// it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency
index = myftol ( tess . shaderTime * bundle - > imageAnimationSpeed * FUNCTABLE_SIZE ) ;
index > > = FUNCTABLE_SIZE2 ;
if ( index < 0 ) {
index = 0 ; // may happen with shader time offsets
}
if ( bundle - > oneShotAnimMap )
{
if ( index > = bundle - > numImageAnimations )
{
// stick on last frame
index = bundle - > numImageAnimations - 1 ;
}
}
else
{
// loop
index % = bundle - > numImageAnimations ;
}
GL_Bind ( bundle - > image [ index ] ) ;
}
/*
= = = = = = = = = = = = = = = =
DrawTris
Draws triangle outlines for debugging
= = = = = = = = = = = = = = = =
*/
static void DrawTris ( shaderCommands_t * input ) {
GL_Bind ( tr . whiteImage ) ;
qglColor3f ( 1 , 1 , 1 ) ;
GL_State ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ) ;
qglDepthRange ( 0 , 0 ) ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglVertexPointer ( 3 , GL_FLOAT , 16 , input - > xyz ) ; // padded for SIMD
if ( qglLockArraysEXT ) {
qglLockArraysEXT ( 0 , input - > numVertexes ) ;
GLimp_LogComment ( " glLockArraysEXT \n " ) ;
}
R_DrawElements ( input - > numIndexes , input - > indexes ) ;
if ( qglUnlockArraysEXT ) {
qglUnlockArraysEXT ( ) ;
GLimp_LogComment ( " glUnlockArraysEXT \n " ) ;
}
qglDepthRange ( 0 , 1 ) ;
}
/*
= = = = = = = = = = = = = = = =
DrawNormals
Draws vertex normals for debugging
= = = = = = = = = = = = = = = =
*/
static void DrawNormals ( shaderCommands_t * input ) {
int i ;
vec3_t temp ;
GL_Bind ( tr . whiteImage ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglDepthRange ( 0 , 0 ) ; // never occluded
GL_State ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE ) ;
qglBegin ( GL_LINES ) ;
for ( i = 0 ; i < input - > numVertexes ; i + + ) {
qglVertex3fv ( input - > xyz [ i ] ) ;
VectorMA ( input - > xyz [ i ] , 2 , input - > normal [ i ] , temp ) ;
qglVertex3fv ( temp ) ;
}
qglEnd ( ) ;
qglDepthRange ( 0 , 1 ) ;
}
/*
= = = = = = = = = = = = = =
RB_BeginSurface
We must set some things up before beginning any tesselation ,
because a surface may be forced to perform a RB_End due
to overflow .
= = = = = = = = = = = = = =
*/
void RB_BeginSurface ( shader_t * shader , int fogNum ) {
shader_t * state = ( shader - > remappedShader ) ? shader - > remappedShader : shader ;
tess . numIndexes = 0 ;
tess . numVertexes = 0 ;
tess . shader = state ;
tess . fogNum = fogNum ;
tess . dlightBits = 0 ; // will be OR'd in by surface functions
tess . xstages = state - > stages ;
tess . numPasses = state - > numUnfoggedPasses ;
tess . currentStageIteratorFunc = state - > optimalStageIteratorFunc ;
tess . shaderTime = backEnd . refdef . floatTime - tess . shader - > timeOffset ;
if ( tess . shader - > clampTime & & tess . shaderTime > = tess . shader - > clampTime ) {
tess . shaderTime = tess . shader - > clampTime ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
DrawMultitextured
output = t0 * t1 or t0 + t1
t0 = most upstream according to spec
t1 = most downstream according to spec
= = = = = = = = = = = = = = = = = = =
*/
static void DrawMultitextured ( shaderCommands_t * input , int stage ) {
shaderStage_t * pStage ;
pStage = tess . xstages [ stage ] ;
GL_State ( pStage - > stateBits ) ;
// this is an ugly hack to work around a GeForce driver
// bug with multitexture and clip planes
if ( backEnd . viewParms . isPortal ) {
qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
}
//
// base
//
GL_SelectTexture ( 0 ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , input - > svars . texcoords [ 0 ] ) ;
R_BindAnimatedImage ( & pStage - > bundle [ 0 ] ) ;
//
// lightmap/secondary pass
//
GL_SelectTexture ( 1 ) ;
qglEnable ( GL_TEXTURE_2D ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
if ( r_lightmap - > integer ) {
GL_TexEnv ( GL_REPLACE ) ;
} else {
GL_TexEnv ( tess . shader - > multitextureEnv ) ;
}
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , input - > svars . texcoords [ 1 ] ) ;
R_BindAnimatedImage ( & pStage - > bundle [ 1 ] ) ;
R_DrawElements ( input - > numIndexes , input - > indexes ) ;
//
// disable texturing on TEXTURE1, then select TEXTURE0
//
//qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
qglDisable ( GL_TEXTURE_2D ) ;
GL_SelectTexture ( 0 ) ;
}
inline int VectorToInt ( vec3_t vec )
{
int tmp , retval ;
_asm
{
push edx
mov edx , [ vec ]
fld dword ptr [ edx + 0 ]
fld dword ptr [ edx + 4 ]
fld dword ptr [ edx + 8 ]
mov eax , 0xff00
fistp tmp
mov al , byte ptr [ tmp ]
shl eax , 16
fistp tmp
mov ah , byte ptr [ tmp ]
fistp tmp
mov al , byte ptr [ tmp ]
mov [ retval ] , eax
pop edx
}
return ( retval ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
NewProjectDlightTexture
Perform dynamic lighting with another rendering pass
= = = = = = = = = = = = = = = = = = =
*/
static void NewProjectDlightTexture ( void )
{
int i , l ;
vec3_t origin , projOrigin , projToVert ;
float * texCoords ;
byte * colors ;
byte clipBits [ SHADER_MAX_VERTEXES ] ;
MAC_STATIC float texCoordsArray [ SHADER_MAX_VERTEXES ] [ 2 ] ;
byte colorArray [ SHADER_MAX_VERTEXES ] [ 4 ] ;
unsigned hitIndexes [ SHADER_MAX_INDEXES ] ;
int numIndexes ;
float scale ;
float radius ;
vec3_t floatColor , coefBasis2 , coefBasis3 ;
float texcoord0 , texcoord1 , coef = 0.0085f * 30.0f , invRadius = 1.0f ;
if ( ! backEnd . refdef . num_dlights )
{
return ;
}
for ( l = 0 ; l < backEnd . refdef . num_dlights ; l + + )
{
dlight_t * dl ;
if ( ! ( tess . dlightBits & ( 1 < < l ) ) )
{
continue ; // this surface definately doesn't have any of this light
}
{
colors = colorArray [ 0 ] ;
texCoords = texCoordsArray [ 0 ] ;
}
dl = & backEnd . refdef . dlights [ l ] ;
VectorCopy ( dl - > transformed , origin ) ;
VectorCopy ( dl - > mProjTransformed , projOrigin ) ;
invRadius = 1.0f / dl - > mProjRadius ;
VectorScale ( dl - > mBasis2 , coef * invRadius , coefBasis2 ) ;
VectorScale ( dl - > mBasis3 , coef * invRadius , coefBasis3 ) ;
radius = dl - > radius ;
scale = 1.0f / radius ;
int intcolor ;
floatColor [ 0 ] = dl - > color [ 0 ] * 255 ;
floatColor [ 1 ] = dl - > color [ 1 ] * 255 ;
floatColor [ 2 ] = dl - > color [ 2 ] * 255 ;
intcolor = VectorToInt ( floatColor ) ;
// RB_BypassXYZCollapse(); // do the copy into tess, because something wants to read it
for ( i = 0 ; i < tess . numVertexes ; i + + , texCoords + = 2 , colors + = 4 )
{
vec3_t dist , dest ;
int clip ;
float modulate ;
backEnd . pc . c_dlightVertexes + + ;
VectorSubtract ( origin , tess . xyz [ i ] , dist ) ;
clip = 0 ;
if ( dl - > mType = = DLIGHT_PROJECTED )
{
// if this vertex is behind the projection origin of the light, give it texcoords of some unlit corner of the light texture
//so it appears unlit
VectorSubtract ( tess . xyz [ i ] , projOrigin , projToVert ) ;
// use the actual radius of the light here
texCoords [ 0 ] = texcoord0 = 0.5f + DotProduct ( dist , coefBasis2 ) ;
texCoords [ 1 ] = texcoord1 = 0.5f + DotProduct ( dist , coefBasis3 ) ;
}
else
{
texCoords [ 0 ] = texcoord0 = 0.5f + dist [ 0 ] * scale ;
texCoords [ 1 ] = texcoord1 = 0.5f + dist [ 1 ] * scale ;
}
if ( texcoord0 < 0.0f )
{
clip | = 1 ;
}
else if ( texcoord0 > 1.0f )
{
clip | = 2 ;
}
if ( texcoord1 < 0.0f )
{
clip | = 4 ;
}
else if ( texcoord1 > 1.0f )
{
clip | = 8 ;
}
clipBits [ i ] = clip ;
if ( dl - > mType = = DLIGHT_PROJECTED )
{
* ( int * ) colors = intcolor ;
}
else
{
// modulate the strength based on the height and color
if ( dist [ 2 ] > radius )
{
clip | = 16 ;
modulate = 0 ;
}
else if ( dist [ 2 ] < - radius )
{
clip | = 32 ;
modulate = 0 ;
}
else
{
if ( dist [ 2 ] < 0.0f )
{
dist [ 2 ] = - dist [ 2 ] ;
}
if ( dist [ 2 ] < radius * 0.5f )
{
modulate = 1.0f ;
}
else
{
modulate = 2.0 * ( radius - dist [ 2 ] ) * scale ;
}
}
VectorScale ( floatColor , modulate , dest ) ;
* ( int * ) colors = VectorToInt ( dest ) ;
}
}
// RB_BypassIndeciesCollapse(); // need to get indecies sorted if they aren't already
// build a list of triangles that need light
numIndexes = 0 ;
for ( i = 0 ; i < tess . numIndexes ; i + = 3 )
{
int a , b , c ;
a = tess . indexes [ i ] ;
b = tess . indexes [ i + 1 ] ;
c = tess . indexes [ i + 2 ] ;
if ( clipBits [ a ] & clipBits [ b ] & clipBits [ c ] )
{
continue ; // not lighted
}
hitIndexes [ numIndexes ] = a ;
hitIndexes [ numIndexes + 1 ] = b ;
hitIndexes [ numIndexes + 2 ] = c ;
numIndexes + = 3 ;
}
if ( ! numIndexes )
{
continue ;
}
if ( qglActiveTextureARB )
{
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ) ;
GL_SelectTexture ( 0 ) ;
R_BindAnimatedImage ( tess . shader - > stages [ tess . shader - > lastNonDetailStage ] - > bundle ) ;
GL_SelectTexture ( 1 ) ;
qglEnable ( GL_TEXTURE_2D ) ;
GL_TexEnv ( GL_MODULATE ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
{
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , colorArray ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , texCoordsArray [ 0 ] ) ;
}
GL_Bind ( tr . dlightImage ) ;
R_DrawElements ( numIndexes , hitIndexes ) ;
// turn off the multitexture unit
qglDisable ( GL_TEXTURE_2D ) ;
GL_SelectTexture ( 0 ) ;
}
else
{
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
{
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , colorArray ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , texCoordsArray [ 0 ] ) ;
}
GL_Bind ( tr . dlightImage ) ;
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ) ;
R_DrawElements ( numIndexes , hitIndexes ) ;
}
backEnd . pc . c_totalIndexes + = numIndexes ;
backEnd . pc . c_dlightIndexes + = numIndexes ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
ProjectDlightTexture
Perform dynamic lighting with another rendering pass
= = = = = = = = = = = = = = = = = = =
*/
static void ProjectDlightTexture ( void ) {
int i , l ;
vec3_t origin ;
float * texCoords ;
byte * colors ;
byte clipBits [ SHADER_MAX_VERTEXES ] ;
MAC_STATIC float texCoordsArray [ SHADER_MAX_VERTEXES ] [ 2 ] ;
byte colorArray [ SHADER_MAX_VERTEXES ] [ 4 ] ;
unsigned hitIndexes [ SHADER_MAX_INDEXES ] ;
int numIndexes ;
float scale ;
float radius ;
vec3_t floatColor ;
if ( ! backEnd . refdef . num_dlights ) {
return ;
}
if ( r_newDLights - > integer )
{
NewProjectDlightTexture ( ) ;
return ;
}
for ( l = 0 ; l < backEnd . refdef . num_dlights ; l + + ) {
dlight_t * dl ;
if ( ! ( tess . dlightBits & ( 1 < < l ) ) ) {
continue ; // this surface definately doesn't have any of this light
}
texCoords = texCoordsArray [ 0 ] ;
colors = colorArray [ 0 ] ;
dl = & backEnd . refdef . dlights [ l ] ;
VectorCopy ( dl - > transformed , origin ) ;
radius = dl - > radius ;
scale = 1.0f / radius ;
floatColor [ 0 ] = dl - > color [ 0 ] * 255.0f ;
floatColor [ 1 ] = dl - > color [ 1 ] * 255.0f ;
floatColor [ 2 ] = dl - > color [ 2 ] * 255.0f ;
for ( i = 0 ; i < tess . numVertexes ; i + + , texCoords + = 2 , colors + = 4 ) {
vec3_t dist ;
int clip ;
float modulate ;
backEnd . pc . c_dlightVertexes + + ;
VectorSubtract ( origin , tess . xyz [ i ] , dist ) ;
texCoords [ 0 ] = 0.5f + dist [ 0 ] * scale ;
texCoords [ 1 ] = 0.5f + dist [ 1 ] * scale ;
clip = 0 ;
if ( texCoords [ 0 ] < 0.0f ) {
clip | = 1 ;
} else if ( texCoords [ 0 ] > 1.0f ) {
clip | = 2 ;
}
if ( texCoords [ 1 ] < 0.0f ) {
clip | = 4 ;
} else if ( texCoords [ 1 ] > 1.0f ) {
clip | = 8 ;
}
// modulate the strength based on the height and color
if ( dist [ 2 ] > radius ) {
clip | = 16 ;
modulate = 0.0f ;
} else if ( dist [ 2 ] < - radius ) {
clip | = 32 ;
modulate = 0.0f ;
} else {
dist [ 2 ] = Q_fabs ( dist [ 2 ] ) ;
if ( dist [ 2 ] < radius * 0.5f ) {
modulate = 1.0f ;
} else {
modulate = 2.0f * ( radius - dist [ 2 ] ) * scale ;
}
}
clipBits [ i ] = clip ;
colors [ 0 ] = myftol ( floatColor [ 0 ] * modulate ) ;
colors [ 1 ] = myftol ( floatColor [ 1 ] * modulate ) ;
colors [ 2 ] = myftol ( floatColor [ 2 ] * modulate ) ;
colors [ 3 ] = 255 ;
}
// build a list of triangles that need light
numIndexes = 0 ;
for ( i = 0 ; i < tess . numIndexes ; i + = 3 ) {
int a , b , c ;
a = tess . indexes [ i ] ;
b = tess . indexes [ i + 1 ] ;
c = tess . indexes [ i + 2 ] ;
if ( clipBits [ a ] & clipBits [ b ] & clipBits [ c ] ) {
continue ; // not lighted
}
hitIndexes [ numIndexes ] = a ;
hitIndexes [ numIndexes + 1 ] = b ;
hitIndexes [ numIndexes + 2 ] = c ;
numIndexes + = 3 ;
}
if ( ! numIndexes ) {
continue ;
}
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , texCoordsArray [ 0 ] ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , colorArray ) ;
GL_Bind ( tr . dlightImage ) ;
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered
if ( dl - > additive ) {
GL_State ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ) ;
}
else {
GL_State ( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ) ;
}
R_DrawElements ( numIndexes , hitIndexes ) ;
backEnd . pc . c_totalIndexes + = numIndexes ;
backEnd . pc . c_dlightIndexes + = numIndexes ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
RB_FogPass
Blends a fog texture on top of everything else
= = = = = = = = = = = = = = = = = = =
*/
static void RB_FogPass ( void ) {
fog_t * fog ;
int i ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , tess . svars . colors ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , tess . svars . texcoords [ 0 ] ) ;
fog = tr . world - > fogs + tess . fogNum ;
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
* ( int * ) & tess . svars . colors [ i ] = fog - > colorInt ;
}
RB_CalcFogTexCoords ( ( float * ) tess . svars . texcoords [ 0 ] ) ;
GL_Bind ( tr . fogImage ) ;
if ( tess . shader - > fogPass = = FP_EQUAL ) {
GL_State ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ) ;
} else {
GL_State ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ;
}
R_DrawElements ( tess . numIndexes , tess . indexes ) ;
}
/*
= = = = = = = = = = = = = = =
ComputeColors
= = = = = = = = = = = = = = =
*/
static void ComputeColors ( shaderStage_t * pStage , int forceRGBGen )
{
int i ;
color4ub_t * colors = tess . svars . colors ;
qboolean killGen = qfalse ;
if ( tess . shader ! = tr . projectionShadowShader & & tess . shader ! = tr . shadowShader & &
( backEnd . currentEntity - > e . renderfx & ( RF_DISINTEGRATE1 | RF_DISINTEGRATE2 ) ) )
{
RB_CalcDisintegrateColors ( ( unsigned char * ) tess . svars . colors ) ;
RB_CalcDisintegrateVertDeform ( ) ;
// We've done some custom alpha and color stuff, so we can skip the rest. Let it do fog though
killGen = qtrue ;
}
//
// rgbGen
//
if ( ! forceRGBGen )
{
forceRGBGen = pStage - > rgbGen ;
}
if ( backEnd . currentEntity - > e . renderfx & RF_VOLUMETRIC ) // does not work for rotated models, technically, this should also be a CGEN type, but that would entail adding new shader commands....which is too much work for one thing
{
int i ;
float * normal , dot ;
unsigned char * color ;
int numVertexes ;
normal = tess . normal [ 0 ] ;
color = tess . svars . colors [ 0 ] ;
numVertexes = tess . numVertexes ;
for ( i = 0 ; i < numVertexes ; i + + , normal + = 4 , color + = 4 )
{
dot = DotProduct ( normal , backEnd . refdef . viewaxis [ 0 ] ) ;
dot * = dot * dot * dot ;
if ( dot < 0.2f ) // so low, so just clamp it
{
dot = 0.0f ;
}
color [ 0 ] = color [ 1 ] = color [ 2 ] = color [ 3 ] = myftol ( backEnd . currentEntity - > e . shaderRGBA [ 0 ] * ( 1 - dot ) ) ;
}
killGen = qtrue ;
}
if ( killGen )
{
goto avoidGen ;
}
//
// rgbGen
//
switch ( forceRGBGen )
{
case CGEN_IDENTITY :
Com_Memset ( tess . svars . colors , 0xff , tess . numVertexes * 4 ) ;
break ;
default :
case CGEN_IDENTITY_LIGHTING :
Com_Memset ( tess . svars . colors , tr . identityLightByte , tess . numVertexes * 4 ) ;
break ;
case CGEN_LIGHTING_DIFFUSE :
RB_CalcDiffuseColor ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case CGEN_EXACT_VERTEX :
Com_Memcpy ( tess . svars . colors , tess . vertexColors , tess . numVertexes * sizeof ( tess . vertexColors [ 0 ] ) ) ;
break ;
case CGEN_CONST :
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
* ( int * ) tess . svars . colors [ i ] = * ( int * ) pStage - > constantColor ;
}
break ;
case CGEN_VERTEX :
if ( tr . identityLight = = 1 )
{
Com_Memcpy ( tess . svars . colors , tess . vertexColors , tess . numVertexes * sizeof ( tess . vertexColors [ 0 ] ) ) ;
}
else
{
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
tess . svars . colors [ i ] [ 0 ] = tess . vertexColors [ i ] [ 0 ] * tr . identityLight ;
tess . svars . colors [ i ] [ 1 ] = tess . vertexColors [ i ] [ 1 ] * tr . identityLight ;
tess . svars . colors [ i ] [ 2 ] = tess . vertexColors [ i ] [ 2 ] * tr . identityLight ;
tess . svars . colors [ i ] [ 3 ] = tess . vertexColors [ i ] [ 3 ] ;
}
}
break ;
case CGEN_ONE_MINUS_VERTEX :
if ( tr . identityLight = = 1 )
{
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
tess . svars . colors [ i ] [ 0 ] = 255 - tess . vertexColors [ i ] [ 0 ] ;
tess . svars . colors [ i ] [ 1 ] = 255 - tess . vertexColors [ i ] [ 1 ] ;
tess . svars . colors [ i ] [ 2 ] = 255 - tess . vertexColors [ i ] [ 2 ] ;
}
}
else
{
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
tess . svars . colors [ i ] [ 0 ] = ( 255 - tess . vertexColors [ i ] [ 0 ] ) * tr . identityLight ;
tess . svars . colors [ i ] [ 1 ] = ( 255 - tess . vertexColors [ i ] [ 1 ] ) * tr . identityLight ;
tess . svars . colors [ i ] [ 2 ] = ( 255 - tess . vertexColors [ i ] [ 2 ] ) * tr . identityLight ;
}
}
break ;
case CGEN_FOG :
{
fog_t * fog ;
fog = tr . world - > fogs + tess . fogNum ;
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
* ( int * ) & tess . svars . colors [ i ] = fog - > colorInt ;
}
}
break ;
case CGEN_WAVEFORM :
RB_CalcWaveColor ( & pStage - > rgbWave , ( unsigned char * ) tess . svars . colors ) ;
break ;
case CGEN_ENTITY :
RB_CalcColorFromEntity ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case CGEN_ONE_MINUS_ENTITY :
RB_CalcColorFromOneMinusEntity ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case CGEN_LIGHTMAP0 :
memset ( colors , 0xff , tess . numVertexes * 4 ) ;
break ;
case CGEN_LIGHTMAP1 :
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
* ( unsigned * ) & colors [ i ] = * ( unsigned * ) styleColors [ pStage - > lightmapStyle ] ;
}
break ;
case CGEN_LIGHTMAP2 :
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
* ( unsigned * ) & colors [ i ] = * ( unsigned * ) styleColors [ pStage - > lightmapStyle ] ;
}
break ;
case CGEN_LIGHTMAP3 :
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
* ( unsigned * ) & colors [ i ] = * ( unsigned * ) styleColors [ pStage - > lightmapStyle ] ;
}
break ;
}
//
// alphaGen
//
switch ( pStage - > alphaGen )
{
case AGEN_SKIP :
break ;
case AGEN_IDENTITY :
if ( forceRGBGen ! = CGEN_IDENTITY ) {
if ( ( forceRGBGen = = CGEN_VERTEX & & tr . identityLight ! = 1 ) | |
forceRGBGen ! = CGEN_VERTEX ) {
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
tess . svars . colors [ i ] [ 3 ] = 0xff ;
}
}
}
break ;
case AGEN_CONST :
if ( forceRGBGen ! = CGEN_CONST ) {
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
tess . svars . colors [ i ] [ 3 ] = pStage - > constantColor [ 3 ] ;
}
}
break ;
case AGEN_WAVEFORM :
RB_CalcWaveAlpha ( & pStage - > alphaWave , ( unsigned char * ) tess . svars . colors ) ;
break ;
case AGEN_LIGHTING_SPECULAR :
RB_CalcSpecularAlpha ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case AGEN_ENTITY :
RB_CalcAlphaFromEntity ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case AGEN_ONE_MINUS_ENTITY :
RB_CalcAlphaFromOneMinusEntity ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case AGEN_VERTEX :
if ( forceRGBGen ! = CGEN_VERTEX ) {
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
tess . svars . colors [ i ] [ 3 ] = tess . vertexColors [ i ] [ 3 ] ;
}
}
break ;
case AGEN_ONE_MINUS_VERTEX :
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
tess . svars . colors [ i ] [ 3 ] = 255 - tess . vertexColors [ i ] [ 3 ] ;
}
break ;
case AGEN_PORTAL :
{
unsigned char alpha ;
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
float len ;
vec3_t v ;
VectorSubtract ( tess . xyz [ i ] , backEnd . viewParms . ori . origin , v ) ;
len = VectorLength ( v ) ;
len / = tess . shader - > portalRange ;
if ( len < 0 )
{
alpha = 0 ;
}
else if ( len > 1 )
{
alpha = 0xff ;
}
else
{
alpha = len * 0xff ;
}
tess . svars . colors [ i ] [ 3 ] = alpha ;
}
}
break ;
case AGEN_BLEND :
if ( forceRGBGen ! = CGEN_VERTEX )
{
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
//colors[i][3] = tess.vertexAlphas[i][pStage->index]; // only used on SOF2, needs implementing if you want it
}
}
break ;
}
avoidGen :
//
// fog adjustment for colors to fade out as fog increases
//
if ( tess . fogNum )
{
switch ( pStage - > adjustColorsForFog )
{
case ACFF_MODULATE_RGB :
RB_CalcModulateColorsByFog ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case ACFF_MODULATE_ALPHA :
RB_CalcModulateAlphasByFog ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case ACFF_MODULATE_RGBA :
RB_CalcModulateRGBAsByFog ( ( unsigned char * ) tess . svars . colors ) ;
break ;
case ACFF_NONE :
break ;
}
}
}
/*
= = = = = = = = = = = = = = =
ComputeTexCoords
= = = = = = = = = = = = = = =
*/
static void ComputeTexCoords ( shaderStage_t * pStage ) {
int i ;
int b ;
float * texcoords ;
for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b + + ) {
int tm ;
texcoords = ( float * ) tess . svars . texcoords [ b ] ;
//
// generate the texture coordinates
//
switch ( pStage - > bundle [ b ] . tcGen )
{
case TCGEN_IDENTITY :
Com_Memset ( tess . svars . texcoords [ b ] , 0 , sizeof ( float ) * 2 * tess . numVertexes ) ;
break ;
case TCGEN_TEXTURE :
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
tess . svars . texcoords [ b ] [ i ] [ 0 ] = tess . texCoords [ i ] [ 0 ] [ 0 ] ;
tess . svars . texcoords [ b ] [ i ] [ 1 ] = tess . texCoords [ i ] [ 0 ] [ 1 ] ;
}
break ;
case TCGEN_LIGHTMAP :
for ( i = 0 ; i < tess . numVertexes ; i + + , texcoords + = 2 ) {
texcoords [ 0 ] = tess . texCoords [ i ] [ 1 ] [ 0 ] ;
texcoords [ 1 ] = tess . texCoords [ i ] [ 1 ] [ 1 ] ;
}
break ;
case TCGEN_LIGHTMAP1 :
for ( i = 0 ; i < tess . numVertexes ; i + + , texcoords + = 2 ) {
texcoords [ 0 ] = tess . texCoords [ i ] [ 2 ] [ 0 ] ;
texcoords [ 1 ] = tess . texCoords [ i ] [ 2 ] [ 1 ] ;
}
break ;
case TCGEN_LIGHTMAP2 :
for ( i = 0 ; i < tess . numVertexes ; i + + , texcoords + = 2 ) {
texcoords [ 0 ] = tess . texCoords [ i ] [ 3 ] [ 0 ] ;
texcoords [ 1 ] = tess . texCoords [ i ] [ 3 ] [ 1 ] ;
}
break ;
case TCGEN_LIGHTMAP3 :
for ( i = 0 ; i < tess . numVertexes ; i + + , texcoords + = 2 ) {
texcoords [ 0 ] = tess . texCoords [ i ] [ 4 ] [ 0 ] ;
texcoords [ 1 ] = tess . texCoords [ i ] [ 4 ] [ 1 ] ;
}
break ;
case TCGEN_VECTOR :
for ( i = 0 ; i < tess . numVertexes ; i + + ) {
tess . svars . texcoords [ b ] [ i ] [ 0 ] = DotProduct ( tess . xyz [ i ] , pStage - > bundle [ b ] . tcGenVectors [ 0 ] ) ;
tess . svars . texcoords [ b ] [ i ] [ 1 ] = DotProduct ( tess . xyz [ i ] , pStage - > bundle [ b ] . tcGenVectors [ 1 ] ) ;
}
break ;
case TCGEN_FOG :
RB_CalcFogTexCoords ( ( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TCGEN_ENVIRONMENT_MAPPED :
RB_CalcEnvironmentTexCoords ( ( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TCGEN_BAD :
return ;
}
//
// alter texture coordinates
//
for ( tm = 0 ; tm < pStage - > bundle [ b ] . numTexMods ; tm + + ) {
switch ( pStage - > bundle [ b ] . texMods [ tm ] . type )
{
case TMOD_NONE :
tm = TR_MAX_TEXMODS ; // break out of for loop
break ;
case TMOD_TURBULENT :
RB_CalcTurbulentTexCoords ( & pStage - > bundle [ b ] . texMods [ tm ] . wave ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_ENTITY_TRANSLATE :
RB_CalcScrollTexCoords ( backEnd . currentEntity - > e . shaderTexCoord ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_SCROLL :
RB_CalcScrollTexCoords ( pStage - > bundle [ b ] . texMods [ tm ] . scroll ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_SCALE :
RB_CalcScaleTexCoords ( pStage - > bundle [ b ] . texMods [ tm ] . scale ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_STRETCH :
RB_CalcStretchTexCoords ( & pStage - > bundle [ b ] . texMods [ tm ] . wave ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_TRANSFORM :
RB_CalcTransformTexCoords ( & pStage - > bundle [ b ] . texMods [ tm ] ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
case TMOD_ROTATE :
RB_CalcRotateTexCoords ( pStage - > bundle [ b ] . texMods [ tm ] . rotateSpeed ,
( float * ) tess . svars . texcoords [ b ] ) ;
break ;
default :
ri . Error ( ERR_DROP , " ERROR: unknown texmod '%d' in shader '%s' \n " , pStage - > bundle [ b ] . texMods [ tm ] . type , tess . shader - > name ) ;
break ;
}
}
}
}
void ForceAlpha ( unsigned char * dstColors , int TR_ForceEntAlpha )
{
int i ;
dstColors + = 3 ;
for ( i = 0 ; i < tess . numVertexes ; i + + , dstColors + = 4 )
{
* dstColors = TR_ForceEntAlpha ;
}
}
/*
* * RB_IterateStagesGeneric
*/
static void RB_IterateStagesGeneric ( shaderCommands_t * input )
{
int stage ;
for ( stage = 0 ; stage < MAX_SHADER_STAGES ; stage + + )
{
shaderStage_t * pStage = tess . xstages [ stage ] ;
int forceRGBGen = 0 ;
int stateBits = 0 ;
if ( ! pStage )
{
break ;
}
if ( stage & & r_lightmap - > integer & & ! ( pStage - > bundle [ 0 ] . isLightmap | | pStage - > bundle [ 1 ] . isLightmap | | pStage - > bundle [ 0 ] . vertexLightmap ) )
{
break ;
}
stateBits = pStage - > stateBits ;
if ( backEnd . currentEntity )
{
if ( backEnd . currentEntity - > e . renderfx & RF_DISINTEGRATE1 )
{
// we want to be able to rip a hole in the thing being disintegrated, and by doing the depth-testing it avoids some kinds of artefacts, but will probably introduce others?
stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK_TRUE | GLS_ATEST_GE_C0 ;
}
if ( backEnd . currentEntity - > e . renderfx & RF_RGB_TINT )
{ //want to use RGBGen from ent
forceRGBGen = CGEN_ENTITY ;
}
}
if ( pStage - > ss . surfaceSpriteType )
{
// We check for surfacesprites AFTER drawing everything else
continue ;
}
ComputeColors ( pStage , forceRGBGen ) ;
ComputeTexCoords ( pStage ) ;
if ( ! setArraysOnce )
{
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , input - > svars . colors ) ;
}
//
// do multitexture
//
if ( pStage - > bundle [ 1 ] . image [ 0 ] ! = 0 )
{
DrawMultitextured ( input , stage ) ;
}
else
{
if ( ! setArraysOnce )
{
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , input - > svars . texcoords [ 0 ] ) ;
}
//
// set state
//
if ( pStage - > bundle [ 0 ] . vertexLightmap & & ( r_vertexLight - > integer & & ! r_uiFullScreen - > integer ) & & r_lightmap - > integer )
{
GL_Bind ( tr . whiteImage ) ;
}
else
R_BindAnimatedImage ( & pStage - > bundle [ 0 ] ) ;
if ( backEnd . currentEntity & & ( backEnd . currentEntity - > e . renderfx & RF_FORCE_ENT_ALPHA ) )
{
ForceAlpha ( ( unsigned char * ) tess . svars . colors , backEnd . currentEntity - > e . shaderRGBA [ 3 ] ) ;
GL_State ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ;
}
else
{
GL_State ( stateBits ) ;
}
//
// draw
//
R_DrawElements ( input - > numIndexes , input - > indexes ) ;
}
}
}
/*
* * RB_StageIteratorGeneric
*/
void RB_StageIteratorGeneric ( void )
{
shaderCommands_t * input ;
int stage ;
input = & tess ;
RB_DeformTessGeometry ( ) ;
//
// log this call
//
if ( r_logFile - > integer )
{
// don't just call LogComment, or we will get
// a call to va() every frame!
GLimp_LogComment ( va ( " --- RB_StageIteratorGeneric( %s ) --- \n " , tess . shader - > name ) ) ;
}
//
// set face culling appropriately
//
GL_Cull ( input - > shader - > cullType ) ;
// set polygon offset if necessary
if ( input - > shader - > polygonOffset )
{
qglEnable ( GL_POLYGON_OFFSET_FILL ) ;
qglPolygonOffset ( r_offsetFactor - > value , r_offsetUnits - > value ) ;
}
//
// if there is only a single pass then we can enable color
// and texture arrays before we compile, otherwise we need
// to avoid compiling those arrays since they will change
// during multipass rendering
//
if ( tess . numPasses > 1 | | input - > shader - > multitextureEnv )
{
setArraysOnce = qfalse ;
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
}
else
{
setArraysOnce = qtrue ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , tess . svars . colors ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 0 , tess . svars . texcoords [ 0 ] ) ;
}
//
// lock XYZ
//
qglVertexPointer ( 3 , GL_FLOAT , 16 , input - > xyz ) ; // padded for SIMD
if ( qglLockArraysEXT )
{
qglLockArraysEXT ( 0 , input - > numVertexes ) ;
GLimp_LogComment ( " glLockArraysEXT \n " ) ;
}
//
// enable color and texcoord arrays after the lock if necessary
//
if ( ! setArraysOnce )
{
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglEnableClientState ( GL_COLOR_ARRAY ) ;
}
//
// call shader function
//
RB_IterateStagesGeneric ( input ) ;
//
// now do any dynamic lighting needed
//
if ( tess . dlightBits & & tess . shader - > sort < = SS_OPAQUE
& & ! ( tess . shader - > surfaceFlags & ( SURF_NODLIGHT | SURF_SKY ) ) ) {
ProjectDlightTexture ( ) ;
}
//
// now do fog
//
if ( tess . fogNum & & tess . shader - > fogPass ) {
RB_FogPass ( ) ;
}
//
// unlock arrays
//
if ( qglUnlockArraysEXT )
{
qglUnlockArraysEXT ( ) ;
GLimp_LogComment ( " glUnlockArraysEXT \n " ) ;
}
//
// reset polygon offset
//
if ( input - > shader - > polygonOffset )
{
qglDisable ( GL_POLYGON_OFFSET_FILL ) ;
}
// Now check for surfacesprites.
if ( r_surfaceSprites - > integer )
{
for ( stage = 1 ; stage < MAX_SHADER_STAGES ; stage + + )
{
if ( ! tess . xstages [ stage ] )
{
break ;
}
if ( tess . xstages [ stage ] - > ss . surfaceSpriteType )
{ // Draw the surfacesprite
RB_DrawSurfaceSprites ( tess . xstages [ stage ] , input ) ;
}
}
}
}
/*
* * RB_StageIteratorVertexLitTexture
*/
void RB_StageIteratorVertexLitTexture ( void )
{
shaderCommands_t * input ;
shader_t * shader ;
int stage ;
input = & tess ;
shader = input - > shader ;
//
// compute colors
//
RB_CalcDiffuseColor ( ( unsigned char * ) tess . svars . colors ) ;
//
// log this call
//
if ( r_logFile - > integer )
{
// don't just call LogComment, or we will get
// a call to va() every frame!
GLimp_LogComment ( va ( " --- RB_StageIteratorVertexLitTexturedUnfogged( %s ) --- \n " , tess . shader - > name ) ) ;
}
//
// set face culling appropriately
//
GL_Cull ( input - > shader - > cullType ) ;
//
// set arrays and lock
//
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , tess . svars . colors ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 16 , tess . texCoords [ 0 ] [ 0 ] ) ;
qglVertexPointer ( 3 , GL_FLOAT , 16 , input - > xyz ) ;
if ( qglLockArraysEXT )
{
qglLockArraysEXT ( 0 , input - > numVertexes ) ;
GLimp_LogComment ( " glLockArraysEXT \n " ) ;
}
//
// call special shade routine
//
R_BindAnimatedImage ( & tess . xstages [ 0 ] - > bundle [ 0 ] ) ;
GL_State ( tess . xstages [ 0 ] - > stateBits ) ;
R_DrawElements ( input - > numIndexes , input - > indexes ) ;
//
// now do any dynamic lighting needed
//
if ( tess . dlightBits & & tess . shader - > sort < = SS_OPAQUE ) {
ProjectDlightTexture ( ) ;
}
//
// now do fog
//
if ( tess . fogNum & & tess . shader - > fogPass ) {
RB_FogPass ( ) ;
}
//
// unlock arrays
//
if ( qglUnlockArraysEXT )
{
qglUnlockArraysEXT ( ) ;
GLimp_LogComment ( " glUnlockArraysEXT \n " ) ;
}
// Now check for surfacesprites.
if ( r_surfaceSprites - > integer )
{
for ( stage = 1 ; stage < MAX_SHADER_STAGES ; stage + + )
{
if ( ! tess . xstages [ stage ] )
{
break ;
}
if ( tess . xstages [ stage ] - > ss . surfaceSpriteType )
{ // Draw the surfacesprite
RB_DrawSurfaceSprites ( tess . xstages [ stage ] , input ) ;
}
}
}
}
//define REPLACE_MODE
void RB_StageIteratorLightmappedMultitexture ( void ) {
shaderCommands_t * input ;
int stage ;
input = & tess ;
//
// log this call
//
if ( r_logFile - > integer ) {
// don't just call LogComment, or we will get
// a call to va() every frame!
GLimp_LogComment ( va ( " --- RB_StageIteratorLightmappedMultitexture( %s ) --- \n " , tess . shader - > name ) ) ;
}
//
// set face culling appropriately
//
GL_Cull ( input - > shader - > cullType ) ;
//
// set color, pointers, and lock
//
GL_State ( GLS_DEFAULT ) ;
qglVertexPointer ( 3 , GL_FLOAT , 16 , input - > xyz ) ;
# ifdef REPLACE_MODE
qglDisableClientState ( GL_COLOR_ARRAY ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglShadeModel ( GL_FLAT ) ;
# else
qglEnableClientState ( GL_COLOR_ARRAY ) ;
qglColorPointer ( 4 , GL_UNSIGNED_BYTE , 0 , tess . constantColor255 ) ;
# endif
//
// select base stage
//
GL_SelectTexture ( 0 ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
R_BindAnimatedImage ( & tess . xstages [ 0 ] - > bundle [ 0 ] ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 16 , tess . texCoords [ 0 ] [ 0 ] ) ;
//
// configure second stage
//
GL_SelectTexture ( 1 ) ;
qglEnable ( GL_TEXTURE_2D ) ;
if ( r_lightmap - > integer ) {
GL_TexEnv ( GL_REPLACE ) ;
} else {
GL_TexEnv ( GL_MODULATE ) ;
}
R_BindAnimatedImage ( & tess . xstages [ 0 ] - > bundle [ 1 ] ) ;
qglEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
qglTexCoordPointer ( 2 , GL_FLOAT , 16 , tess . texCoords [ 0 ] [ 1 ] ) ;
//
// lock arrays
//
if ( qglLockArraysEXT ) {
qglLockArraysEXT ( 0 , input - > numVertexes ) ;
GLimp_LogComment ( " glLockArraysEXT \n " ) ;
}
R_DrawElements ( input - > numIndexes , input - > indexes ) ;
//
// disable texturing on TEXTURE1, then select TEXTURE0
//
qglDisable ( GL_TEXTURE_2D ) ;
qglDisableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
GL_SelectTexture ( 0 ) ;
# ifdef REPLACE_MODE
GL_TexEnv ( GL_MODULATE ) ;
qglShadeModel ( GL_SMOOTH ) ;
# endif
//
// now do any dynamic lighting needed
//
if ( tess . dlightBits & & tess . shader - > sort < = SS_OPAQUE ) {
ProjectDlightTexture ( ) ;
}
//
// now do fog
//
if ( tess . fogNum & & tess . shader - > fogPass ) {
RB_FogPass ( ) ;
}
//
// unlock arrays
//
if ( qglUnlockArraysEXT ) {
qglUnlockArraysEXT ( ) ;
GLimp_LogComment ( " glUnlockArraysEXT \n " ) ;
}
// Now check for surfacesprites.
if ( r_surfaceSprites - > integer )
{
for ( stage = 1 ; stage < MAX_SHADER_STAGES ; stage + + )
{
if ( ! tess . xstages [ stage ] )
{
break ;
}
if ( tess . xstages [ stage ] - > ss . surfaceSpriteType )
{ // Draw the surfacesprite
RB_DrawSurfaceSprites ( tess . xstages [ stage ] , input ) ;
}
}
}
}
/*
* * RB_EndSurface
*/
void RB_EndSurface ( void ) {
shaderCommands_t * input ;
input = & tess ;
if ( input - > numIndexes = = 0 ) {
return ;
}
if ( input - > indexes [ SHADER_MAX_INDEXES - 1 ] ! = 0 ) {
ri . Error ( ERR_DROP , " RB_EndSurface() - SHADER_MAX_INDEXES hit " ) ;
}
if ( input - > xyz [ SHADER_MAX_VERTEXES - 1 ] [ 0 ] ! = 0 ) {
ri . Error ( ERR_DROP , " RB_EndSurface() - SHADER_MAX_VERTEXES hit " ) ;
}
if ( tess . shader = = tr . shadowShader ) {
RB_ShadowTessEnd ( ) ;
return ;
}
// for debugging of sort order issues, stop rendering after a given sort value
if ( r_debugSort - > integer & & r_debugSort - > integer < tess . shader - > sort ) {
return ;
}
//
// update performance counters
//
backEnd . pc . c_shaders + + ;
backEnd . pc . c_vertexes + = tess . numVertexes ;
backEnd . pc . c_indexes + = tess . numIndexes ;
backEnd . pc . c_totalIndexes + = tess . numIndexes * tess . numPasses ;
if ( tess . fogNum & & tess . shader - > fogPass > FP_NONE & & tess . shader - > fogPass < FP_GLFOG ) // && r_drawfog->value)
{
backEnd . pc . c_totalIndexes + = tess . numIndexes ;
}
//
// call off to shader specific tess end function
//
tess . currentStageIteratorFunc ( ) ;
//
// draw debugging stuff
//
if ( r_showtris - > integer & & com_developer - > integer ) {
DrawTris ( input ) ;
}
if ( r_shownormals - > integer & & com_developer - > integer ) {
DrawNormals ( input ) ;
}
// clear shader so we can tell we don't have any unclosed surfaces
tess . numIndexes = 0 ;
GLimp_LogComment ( " ---------- \n " ) ;
}