ioq3/code/renderergl2/tr_shade.c

1867 lines
46 KiB
C
Raw Normal View History

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena 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.
Quake III Arena 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 Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_shade.c
#include "tr_local.h"
#if idppc_altivec && !defined(MACOS_X)
#include <altivec.h>
#endif
/*
THIS ENTIRE FILE IS BACK END
This file deals with applying shaders to surface data in the tess struct.
*/
/*
==================
R_DrawElements
==================
*/
void R_DrawElementsVBO( int numIndexes, glIndex_t firstIndex, glIndex_t minIndex, glIndex_t maxIndex )
{
if (glRefConfig.drawRangeElements)
qglDrawRangeElementsEXT(GL_TRIANGLES, minIndex, maxIndex, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE)));
else
qglDrawElements(GL_TRIANGLES, numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(firstIndex * sizeof(GL_INDEX_TYPE)));
}
static void R_DrawMultiElementsVBO( int multiDrawPrimitives, glIndex_t *multiDrawMinIndex, glIndex_t *multiDrawMaxIndex,
GLsizei *multiDrawNumIndexes, glIndex_t **multiDrawFirstIndex)
{
if (glRefConfig.multiDrawArrays)
{
qglMultiDrawElementsEXT(GL_TRIANGLES, multiDrawNumIndexes, GL_INDEX_TYPE, (const GLvoid **)multiDrawFirstIndex, multiDrawPrimitives);
}
else
{
int i;
if (glRefConfig.drawRangeElements)
{
for (i = 0; i < multiDrawPrimitives; i++)
{
qglDrawRangeElementsEXT(GL_TRIANGLES, multiDrawMinIndex[i], multiDrawMaxIndex[i], multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]);
}
}
else
{
for (i = 0; i < multiDrawPrimitives; i++)
{
qglDrawElements(GL_TRIANGLES, multiDrawNumIndexes[i], GL_INDEX_TYPE, multiDrawFirstIndex[i]);
}
}
}
}
/*
=============================================================
SURFACE SHADERS
=============================================================
*/
shaderCommands_t tess;
/*
=================
R_BindAnimatedImageToTMU
=================
*/
static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index;
if ( bundle->isVideoMap ) {
int oldtmu = glState.currenttmu;
GL_SelectTexture(tmu);
ri.CIN_RunCinematic(bundle->videoMapHandle);
ri.CIN_UploadCinematic(bundle->videoMapHandle);
GL_SelectTexture(oldtmu);
return;
}
if ( bundle->numImageAnimations <= 1 ) {
GL_BindToTMU( bundle->image[0], tmu);
return;
}
// it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency
index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
index >>= FUNCTABLE_SIZE2;
if ( index < 0 ) {
index = 0; // may happen with shader time offsets
}
index %= bundle->numImageAnimations;
GL_BindToTMU( bundle->image[ index ], tmu );
}
/*
================
DrawTris
Draws triangle outlines for debugging
================
*/
static void DrawTris (shaderCommands_t *input) {
GL_Bind( tr.whiteImage );
GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
qglDepthRange( 0, 0 );
{
shaderProgram_t *sp = &tr.textureColorShader;
vec4_t color;
GLSL_VertexAttribsState(ATTR_POSITION);
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
VectorSet4(color, 1, 1, 1, 1);
GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
}
qglDepthRange( 0, 1 );
}
/*
================
DrawNormals
Draws vertex normals for debugging
================
*/
static void DrawNormals (shaderCommands_t *input) {
//FIXME: implement this
}
/*
==============
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.firstIndex = 0;
tess.numVertexes = 0;
tess.multiDrawPrimitives = 0;
tess.shader = state;
tess.fogNum = fogNum;
tess.dlightBits = 0; // will be OR'd in by surface functions
tess.pshadowBits = 0; // will be OR'd in by surface functions
tess.xstages = state->stages;
tess.numPasses = state->numUnfoggedPasses;
tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
tess.useInternalVBO = qtrue;
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
tess.shaderTime = tess.shader->clampTime;
}
if (backEnd.viewParms.flags & VPF_SHADOWMAP)
{
tess.currentStageIteratorFunc = RB_StageIteratorGeneric;
}
}
extern float EvalWaveForm( const waveForm_t *wf );
extern float EvalWaveFormClamped( const waveForm_t *wf );
static void ComputeTexMatrix( shaderStage_t *pStage, int bundleNum, float *outmatrix)
{
int tm;
float matrix[16], currentmatrix[16];
textureBundle_t *bundle = &pStage->bundle[bundleNum];
Matrix16Identity(outmatrix);
Matrix16Identity(currentmatrix);
for ( tm = 0; tm < bundle->numTexMods ; tm++ ) {
switch ( bundle->texMods[tm].type )
{
case TMOD_NONE:
tm = TR_MAX_TEXMODS; // break out of for loop
break;
case TMOD_TURBULENT:
RB_CalcTurbulentTexMatrix( &bundle->texMods[tm].wave,
matrix );
outmatrix[12] = matrix[12];
outmatrix[13] = matrix[13];
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_ENTITY_TRANSLATE:
RB_CalcScrollTexMatrix( backEnd.currentEntity->e.shaderTexCoord,
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_SCROLL:
RB_CalcScrollTexMatrix( bundle->texMods[tm].scroll,
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_SCALE:
RB_CalcScaleTexMatrix( bundle->texMods[tm].scale,
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_STRETCH:
RB_CalcStretchTexMatrix( &bundle->texMods[tm].wave,
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_TRANSFORM:
RB_CalcTransformTexMatrix( &bundle->texMods[tm],
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
case TMOD_ROTATE:
RB_CalcRotateTexMatrix( bundle->texMods[tm].rotateSpeed,
matrix );
Matrix16Multiply(matrix, currentmatrix, outmatrix);
Matrix16Copy(outmatrix, currentmatrix);
break;
default:
ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name );
break;
}
}
}
static void ComputeDeformValues(int *deformGen, vec5_t deformParams)
{
// u_DeformGen
*deformGen = DGEN_NONE;
if(!ShaderRequiresCPUDeforms(tess.shader))
{
deformStage_t *ds;
// only support the first one
ds = &tess.shader->deforms[0];
switch (ds->deformation)
{
case DEFORM_WAVE:
*deformGen = ds->deformationWave.func;
deformParams[0] = ds->deformationWave.base;
deformParams[1] = ds->deformationWave.amplitude;
deformParams[2] = ds->deformationWave.phase;
deformParams[3] = ds->deformationWave.frequency;
deformParams[4] = ds->deformationSpread;
break;
case DEFORM_BULGE:
*deformGen = DGEN_BULGE;
deformParams[0] = 0;
deformParams[1] = ds->bulgeHeight; // amplitude
deformParams[2] = ds->bulgeWidth; // phase
deformParams[3] = ds->bulgeSpeed; // frequency
deformParams[4] = 0;
break;
default:
break;
}
}
}
static void ProjectDlightTexture( void ) {
int l;
vec3_t origin;
float scale;
float radius;
int deformGen;
vec5_t deformParams;
if ( !backEnd.refdef.num_dlights ) {
return;
}
ComputeDeformValues(&deformGen, deformParams);
for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
dlight_t *dl;
shaderProgram_t *sp;
vec4_t vector;
if ( !( tess.dlightBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this light
}
dl = &backEnd.refdef.dlights[l];
VectorCopy( dl->transformed, origin );
radius = dl->radius;
scale = 1.0f / radius;
sp = &tr.dlightShader[deformGen == DGEN_NONE ? 0 : 1];
backEnd.pc.c_dlightDraws++;
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
vector[0] = dl->color[0];
vector[1] = dl->color[1];
vector[2] = dl->color[2];
vector[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector);
vector[0] = origin[0];
vector[1] = origin[1];
vector[2] = origin[2];
vector[3] = scale;
GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector);
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_ATEST_GT_0 | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
}
else {
GL_State( GLS_ATEST_GT_0 | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
}
if (tess.multiDrawPrimitives)
{
shaderCommands_t *input = &tess;
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes;
backEnd.pc.c_dlightIndexes += tess.numIndexes;
}
}
static void ComputeShaderColors( shaderStage_t *pStage, vec4_t baseColor, vec4_t vertColor )
{
//
// rgbGen
//
switch ( pStage->rgbGen )
{
case CGEN_IDENTITY:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 1.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_IDENTITY_LIGHTING:
baseColor[0] =
baseColor[1] =
baseColor[2] = tr.identityLight;
baseColor[3] = 1.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_EXACT_VERTEX:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 0.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 1.0f;
break;
case CGEN_EXACT_VERTEX_LIT:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 0.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 1.0f;
break;
case CGEN_CONST:
baseColor[0] = pStage->constantColor[0] / 255.0f;
baseColor[1] = pStage->constantColor[1] / 255.0f;
baseColor[2] = pStage->constantColor[2] / 255.0f;
baseColor[3] = pStage->constantColor[3] / 255.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_VERTEX:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 0.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] = tr.identityLight;
vertColor[3] = 1.0f;
break;
case CGEN_VERTEX_LIT:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 0.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = tr.identityLight;
break;
case CGEN_ONE_MINUS_VERTEX:
baseColor[0] =
baseColor[1] =
baseColor[2] = tr.identityLight;
baseColor[3] = 1.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] = -tr.identityLight;
vertColor[3] = 0.0f;
break;
case CGEN_FOG:
{
fog_t *fog;
fog = tr.world->fogs + tess.fogNum;
baseColor[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f;
baseColor[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f;
baseColor[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
baseColor[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
}
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_WAVEFORM:
baseColor[0] =
baseColor[1] =
baseColor[2] = RB_CalcWaveColorSingle( &pStage->rgbWave );
baseColor[3] = 1.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_ENTITY:
if (backEnd.currentEntity)
{
baseColor[0] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f;
baseColor[1] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f;
baseColor[2] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f;
baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
}
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_ONE_MINUS_ENTITY:
if (backEnd.currentEntity)
{
baseColor[0] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[0] / 255.0f;
baseColor[1] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[1] / 255.0f;
baseColor[2] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[2] / 255.0f;
baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
}
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
case CGEN_LIGHTING_DIFFUSE:
case CGEN_BAD:
baseColor[0] =
baseColor[1] =
baseColor[2] =
baseColor[3] = 1.0f;
vertColor[0] =
vertColor[1] =
vertColor[2] =
vertColor[3] = 0.0f;
break;
}
//
// alphaGen
//
switch ( pStage->alphaGen )
{
case AGEN_SKIP:
break;
case AGEN_IDENTITY:
baseColor[3] = 1.0f;
vertColor[3] = 0.0f;
break;
case AGEN_CONST:
baseColor[3] = pStage->constantColor[3] / 255.0f;
vertColor[3] = 0.0f;
break;
case AGEN_WAVEFORM:
baseColor[3] = RB_CalcWaveAlphaSingle( &pStage->alphaWave );
vertColor[3] = 0.0f;
break;
case AGEN_ENTITY:
if (backEnd.currentEntity)
{
baseColor[3] = ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
}
vertColor[3] = 0.0f;
break;
case AGEN_ONE_MINUS_ENTITY:
if (backEnd.currentEntity)
{
baseColor[3] = 1.0f - ((unsigned char *)backEnd.currentEntity->e.shaderRGBA)[3] / 255.0f;
}
vertColor[3] = 0.0f;
break;
case AGEN_VERTEX:
baseColor[3] = 0.0f;
vertColor[3] = 1.0f;
break;
case AGEN_ONE_MINUS_VERTEX:
baseColor[3] = 1.0f;
vertColor[3] = -1.0f;
break;
case AGEN_LIGHTING_SPECULAR:
case AGEN_PORTAL:
case AGEN_FRESNEL:
// Done entirely in vertex program
baseColor[3] = 1.0f;
vertColor[3] = 0.0f;
break;
}
// FIXME: find some way to implement this.
#if 0
// if in greyscale rendering mode turn all color values into greyscale.
if(r_greyscale->integer)
{
int scale;
for(i = 0; i < tess.numVertexes; i++)
{
scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3;
tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
}
}
#endif
}
static void ComputeFogValues(vec4_t fogDistanceVector, vec4_t fogDepthVector, float *eyeT)
{
// from RB_CalcFogTexCoords()
fog_t *fog;
vec3_t local;
if (!tess.fogNum)
return;
fog = tr.world->fogs + tess.fogNum;
VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );
fogDistanceVector[0] = -backEnd.or.modelMatrix[2];
fogDistanceVector[1] = -backEnd.or.modelMatrix[6];
fogDistanceVector[2] = -backEnd.or.modelMatrix[10];
fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );
// scale the fog vectors based on the fog's thickness
VectorScale4(fogDistanceVector, fog->tcScale, fogDistanceVector);
// rotate the gradient vector for this orientation
if ( fog->hasSurface ) {
fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] +
fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];
fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] +
fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];
fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] +
fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];
fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );
*eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];
} else {
*eyeT = 1; // non-surface fog always has eye inside
}
}
static void ComputeFogColorMask( shaderStage_t *pStage, vec4_t fogColorMask )
{
switch(pStage->adjustColorsForFog)
{
case ACFF_MODULATE_RGB:
fogColorMask[0] =
fogColorMask[1] =
fogColorMask[2] = 1.0f;
fogColorMask[3] = 0.0f;
break;
case ACFF_MODULATE_ALPHA:
fogColorMask[0] =
fogColorMask[1] =
fogColorMask[2] = 0.0f;
fogColorMask[3] = 1.0f;
break;
case ACFF_MODULATE_RGBA:
fogColorMask[0] =
fogColorMask[1] =
fogColorMask[2] =
fogColorMask[3] = 1.0f;
break;
default:
fogColorMask[0] =
fogColorMask[1] =
fogColorMask[2] =
fogColorMask[3] = 0.0f;
break;
}
}
static void ForwardDlight( void ) {
int l;
//vec3_t origin;
//float scale;
float radius;
int deformGen;
vec5_t deformParams;
vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
float eyeT = 0;
shaderCommands_t *input = &tess;
shaderStage_t *pStage = tess.xstages[0];
if ( !backEnd.refdef.num_dlights ) {
return;
}
ComputeDeformValues(&deformGen, deformParams);
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
dlight_t *dl;
shaderProgram_t *sp;
vec4_t vector;
matrix_t matrix;
if ( !( tess.dlightBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this light
}
dl = &backEnd.refdef.dlights[l];
//VectorCopy( dl->transformed, origin );
radius = dl->radius;
//scale = 1.0f / radius;
//if (pStage->glslShaderGroup == tr.lightallShader)
{
int index = pStage->glslShaderIndex;
index &= ~(LIGHTDEF_LIGHTTYPE_MASK | LIGHTDEF_USE_DELUXEMAP);
index |= LIGHTDEF_USE_LIGHT_VECTOR;
sp = &tr.lightallShader[index];
}
backEnd.pc.c_lightallDraws++;
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
if ( input->fogNum ) {
vec4_t fogColorMask;
GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
ComputeFogColorMask(pStage, fogColorMask);
GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
}
{
vec4_t baseColor;
vec4_t vertColor;
ComputeShaderColors(pStage, baseColor, vertColor);
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
}
if (pStage->alphaGen == AGEN_PORTAL)
{
GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
}
GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);
GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color);
VectorSet(vector, 0, 0, 0);
GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector);
VectorCopy(dl->origin, vector);
vector[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);
GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo);
// 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 );
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
if (pStage->bundle[TB_DIFFUSEMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);
if (pStage->bundle[TB_NORMALMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
if (pStage->bundle[TB_SPECULARMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
if (r_dlightMode->integer >= 2)
{
GL_SelectTexture(TB_SHADOWMAP);
GL_BindCubemap(tr.shadowCubemaps[l]);
GL_SelectTexture(0);
}
ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix );
VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
//
// draw
//
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes;
backEnd.pc.c_dlightIndexes += tess.numIndexes;
}
}
static void ForwardSunlight( void ) {
// int l;
//vec3_t origin;
//float scale;
int stage;
int stageGlState[2];
qboolean alphaOverride = qfalse;
int deformGen;
vec5_t deformParams;
vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
float eyeT = 0;
shaderCommands_t *input = &tess;
ComputeDeformValues(&deformGen, deformParams);
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
// deal with vertex alpha blended surfaces
if (input->xstages[0] && input->xstages[1] &&
(input->xstages[1]->alphaGen == AGEN_VERTEX || input->xstages[1]->alphaGen == AGEN_ONE_MINUS_VERTEX))
{
stageGlState[0] = input->xstages[0]->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
if (stageGlState[0] == 0 || stageGlState[0] == (GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO))
{
stageGlState[1] = input->xstages[1]->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
if (stageGlState[1] == (GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA))
{
alphaOverride = qtrue;
stageGlState[0] = GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
stageGlState[1] = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
}
else if (stageGlState[1] == (GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_SRC_ALPHA))
{
alphaOverride = qtrue;
stageGlState[0] = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
stageGlState[1] = GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
}
}
}
if (!alphaOverride)
{
stageGlState[0] =
stageGlState[1] = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL;
}
for ( stage = 0; stage < 2 /*MAX_SHADER_STAGES */; stage++ )
{
shaderStage_t *pStage = input->xstages[stage];
shaderProgram_t *sp;
vec4_t vector;
matrix_t matrix;
if ( !pStage )
{
break;
}
//VectorCopy( dl->transformed, origin );
//if (pStage->glslShaderGroup == tr.lightallShader)
{
int index = pStage->glslShaderIndex;
index &= ~(LIGHTDEF_LIGHTTYPE_MASK | LIGHTDEF_USE_DELUXEMAP);
index |= LIGHTDEF_USE_LIGHT_VECTOR | LIGHTDEF_USE_SHADOWMAP;
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
index |= LIGHTDEF_ENTITY;
}
sp = &tr.lightallShader[index];
}
backEnd.pc.c_lightallDraws++;
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
if ( input->fogNum ) {
vec4_t fogColorMask;
GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
ComputeFogColorMask(pStage, fogColorMask);
GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
}
{
vec4_t baseColor;
vec4_t vertColor;
ComputeShaderColors(pStage, baseColor, vertColor);
if (alphaOverride)
{
if (input->xstages[1]->alphaGen == AGEN_VERTEX)
{
baseColor[3] = 0.0f;
vertColor[3] = 1.0f;
}
else if (input->xstages[1]->alphaGen == AGEN_ONE_MINUS_VERTEX)
{
baseColor[3] = 1.0f;
vertColor[3] = -1.0f;
}
}
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
}
if (pStage->alphaGen == AGEN_PORTAL)
{
GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
}
GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);
GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, backEnd.refdef.sunCol);
GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, backEnd.refdef.sunAmbCol);
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, backEnd.refdef.sunDir);
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 9999999999.9f);
GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo);
GL_State( stageGlState[stage] );
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
if (pStage->bundle[TB_DIFFUSEMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP);
if (pStage->bundle[TB_NORMALMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP);
if (pStage->bundle[TB_SPECULARMAP].image[0])
R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP);
/*
{
GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP);
GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2);
GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3);
GLSL_SetUniformMatrix16(sp, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]);
GLSL_SetUniformMatrix16(sp, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]);
GLSL_SetUniformMatrix16(sp, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]);
}
*/
GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP);
ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix );
VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
//
// draw
//
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes;
backEnd.pc.c_dlightIndexes += tess.numIndexes;
}
}
static void ProjectPshadowVBOGLSL( void ) {
int l;
vec3_t origin;
float radius;
int deformGen;
vec5_t deformParams;
shaderCommands_t *input = &tess;
if ( !backEnd.refdef.num_pshadows ) {
return;
}
ComputeDeformValues(&deformGen, deformParams);
for ( l = 0 ; l < backEnd.refdef.num_pshadows ; l++ ) {
pshadow_t *ps;
shaderProgram_t *sp;
vec4_t vector;
if ( !( tess.pshadowBits & ( 1 << l ) ) ) {
continue; // this surface definately doesn't have any of this shadow
}
ps = &backEnd.refdef.pshadows[l];
VectorCopy( ps->lightOrigin, origin );
radius = ps->lightRadius;
sp = &tr.pshadowShader;
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
VectorCopy(origin, vector);
vector[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector);
GLSL_SetUniformVec3(sp, UNIFORM_LIGHTFORWARD, vector);
VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector);
GLSL_SetUniformVec3(sp, UNIFORM_LIGHTRIGHT, vector);
VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector);
GLSL_SetUniformVec3(sp, UNIFORM_LIGHTUP, vector);
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius);
// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
// where they aren't rendered
GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
GL_BindToTMU( tr.pshadowMaps[l], TB_DIFFUSEMAP );
//
// draw
//
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
backEnd.pc.c_totalIndexes += tess.numIndexes;
//backEnd.pc.c_dlightIndexes += tess.numIndexes;
}
}
/*
===================
RB_FogPass
Blends a fog texture on top of everything else
===================
*/
static void RB_FogPass( void ) {
fog_t *fog;
vec4_t color;
vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
float eyeT = 0;
shaderProgram_t *sp;
int deformGen;
vec5_t deformParams;
ComputeDeformValues(&deformGen, deformParams);
{
int index = 0;
2012-12-06 21:53:52 +00:00
if (deformGen != DGEN_NONE)
index |= FOGDEF_USE_DEFORM_VERTEXES;
if (glState.vertexAttribsInterpolation)
index |= FOGDEF_USE_VERTEX_ANIMATION;
sp = &tr.fogShader[index];
}
backEnd.pc.c_fogDraws++;
GLSL_BindProgram(sp);
fog = tr.world->fogs + tess.fogNum;
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f;
color[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f;
color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f;
color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f;
GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
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 );
}
if (tess.multiDrawPrimitives)
{
shaderCommands_t *input = &tess;
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex);
}
}
static unsigned int RB_CalcShaderVertexAttribs( shaderCommands_t *input )
{
unsigned int vertexAttribs = input->shader->vertexAttribs;
if(glState.vertexAttribsInterpolation > 0.0f)
{
vertexAttribs |= ATTR_POSITION2;
if (vertexAttribs & ATTR_NORMAL)
{
vertexAttribs |= ATTR_NORMAL2;
#ifdef USE_VERT_TANGENT_SPACE
vertexAttribs |= ATTR_TANGENT2;
vertexAttribs |= ATTR_BITANGENT2;
#endif
}
}
return vertexAttribs;
}
static void RB_IterateStagesGeneric( shaderCommands_t *input )
{
int stage;
matrix_t matrix;
vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
float eyeT = 0;
int deformGen;
vec5_t deformParams;
ComputeDeformValues(&deformGen, deformParams);
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
{
shaderStage_t *pStage = input->xstages[stage];
shaderProgram_t *sp;
if ( !pStage )
{
break;
}
if (backEnd.depthFill)
{
if (pStage->glslShaderGroup)
{
int index = 0;
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
index |= LIGHTDEF_ENTITY;
}
if (pStage->stateBits & GLS_ATEST_BITS)
{
index |= LIGHTDEF_USE_TCGEN_AND_TCMOD;
}
sp = &pStage->glslShaderGroup[index];
}
else
{
int shaderAttribs = 0;
if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader))
{
shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES;
}
if (glState.vertexAttribsInterpolation > 0.0f && backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION;
}
if (pStage->stateBits & GLS_ATEST_BITS)
{
shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD;
}
sp = &tr.genericShader[shaderAttribs];
}
}
else if (pStage->glslShaderGroup)
{
int index = pStage->glslShaderIndex;
if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity)
{
index |= LIGHTDEF_ENTITY;
}
if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP)
{
index = LIGHTDEF_USE_LIGHTMAP;
}
sp = &pStage->glslShaderGroup[index];
if (pStage->glslShaderGroup == tr.lightallShader)
{
backEnd.pc.c_lightallDraws++;
}
}
else
{
sp = GLSL_GetGenericShaderProgram(stage);
backEnd.pc.c_genericDraws++;
}
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
if ( input->fogNum ) {
GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector);
GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector);
GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT);
}
GL_State( pStage->stateBits );
{
vec4_t baseColor;
vec4_t vertColor;
qboolean tint = qtrue;
int stage2;
ComputeShaderColors(pStage, baseColor, vertColor);
for ( stage2 = stage + 1; stage2 < MAX_SHADER_STAGES; stage2++ )
{
shaderStage_t *pStage2 = input->xstages[stage2];
2012-10-26 03:56:45 +00:00
unsigned int srcBlendBits;
//unsigned int dstBlendBits;
if ( !pStage2 )
{
break;
}
srcBlendBits = pStage2->stateBits & GLS_SRCBLEND_BITS;
2012-10-26 03:56:45 +00:00
//dstBlendBits = pStage2->stateBits & GLS_DSTBLEND_BITS;
if (srcBlendBits == GLS_SRCBLEND_DST_COLOR)
{
tint = qfalse;
break;
}
}
if (!((tr.sunShadows || r_forceSun->integer) && tess.shader->sort <= SS_OPAQUE
&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader))
{
tint = qfalse;
}
if (tint)
{
// use VectorScale to only scale first three values, not alpha
VectorScale(baseColor, backEnd.refdef.colorScale, baseColor);
VectorScale(vertColor, backEnd.refdef.colorScale, vertColor);
}
GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor);
GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor);
}
if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE)
{
vec4_t vec;
VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec);
GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec);
VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec);
GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec);
VectorCopy(backEnd.currentEntity->lightDir, vec);
vec[3] = 0.0f;
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec);
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 999999.0f);
}
if (pStage->alphaGen == AGEN_PORTAL)
{
GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange);
}
GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen);
GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen);
if ( input->fogNum )
{
vec4_t fogColorMask;
ComputeFogColorMask(pStage, fogColorMask);
GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask);
}
ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix );
{
vec4_t vector;
VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
}
GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen);
if (pStage->bundle[0].tcGen == TCGEN_VECTOR)
{
vec3_t vec;
VectorCopy(pStage->bundle[0].tcGenVectors[0], vec);
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec);
VectorCopy(pStage->bundle[0].tcGenVectors[1], vec);
GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec);
}
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo);
//GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale);
//
// do multitexture
//
if ( backEnd.depthFill )
{
if (!(pStage->stateBits & GLS_ATEST_BITS))
GL_BindToTMU( tr.whiteImage, 0 );
else if ( pStage->bundle[TB_COLORMAP].image[0] != 0 )
R_BindAnimatedImageToTMU( &pStage->bundle[TB_COLORMAP], TB_COLORMAP );
}
else if ( pStage->glslShaderGroup )
{
int i;
if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0])
{
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{
if (i == TB_LIGHTMAP)
{
R_BindAnimatedImageToTMU( &pStage->bundle[i], i);
}
else if (pStage->bundle[i].image[0])
{
GL_BindToTMU( tr.whiteImage, i);
}
}
}
else if (r_lightmap->integer == 3 && pStage->bundle[TB_DELUXEMAP].image[0])
{
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{
if (i == TB_LIGHTMAP)
{
R_BindAnimatedImageToTMU( &pStage->bundle[TB_DELUXEMAP], i);
}
else if (pStage->bundle[i].image[0])
{
GL_BindToTMU( tr.whiteImage, i);
}
}
}
else
{
for (i = 0; i < NUM_TEXTURE_BUNDLES; i++)
{
if (pStage->bundle[i].image[0])
{
R_BindAnimatedImageToTMU( &pStage->bundle[i], i);
}
}
}
}
else if ( pStage->bundle[1].image[0] != 0 )
{
R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 );
//
// lightmap/secondary pass
//
if ( r_lightmap->integer ) {
GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, GL_REPLACE);
} else {
GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv);
}
R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 );
}
else
{
//
// set state
//
if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer )
{
GL_BindToTMU( tr.whiteImage, 0 );
}
else
R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 );
GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, 0);
}
//
// draw
//
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
// allow skipping out to show just lightmaps during development
if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
{
break;
}
if (backEnd.depthFill)
break;
}
}
static void RB_RenderShadowmap( shaderCommands_t *input )
{
int deformGen;
vec5_t deformParams;
ComputeDeformValues(&deformGen, deformParams);
{
shaderProgram_t *sp = &tr.shadowmapShader;
vec4_t vector;
GLSL_BindProgram(sp);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen);
if (deformGen != DGEN_NONE)
{
GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams);
GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime);
}
VectorCopy(backEnd.viewParms.or.origin, vector);
vector[3] = 1.0f;
GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector);
GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar);
GL_State( 0 );
//
// do multitexture
//
//if ( pStage->glslShaderGroup )
{
//
// draw
//
if (input->multiDrawPrimitives)
{
R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex);
}
else
{
R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex);
}
}
}
}
/*
** RB_StageIteratorGeneric
*/
void RB_StageIteratorGeneric( void )
{
shaderCommands_t *input;
unsigned int vertexAttribs = 0;
input = &tess;
if (!input->numVertexes || !input->numIndexes)
{
return;
}
if (tess.useInternalVBO)
{
RB_DeformTessGeometry();
}
vertexAttribs = RB_CalcShaderVertexAttribs( input );
if (tess.useInternalVBO)
{
RB_UpdateVBOs(vertexAttribs);
}
else
{
backEnd.pc.c_staticVboDraws++;
}
//
// 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
//
if ((backEnd.viewParms.flags & VPF_DEPTHSHADOW))
{
//GL_Cull( CT_TWO_SIDED );
if (input->shader->cullType == CT_TWO_SIDED)
GL_Cull( CT_TWO_SIDED );
else if (input->shader->cullType == CT_FRONT_SIDED)
GL_Cull( CT_BACK_SIDED );
else
GL_Cull( CT_FRONT_SIDED );
}
else
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 );
}
//
// Set vertex attribs and pointers
//
GLSL_VertexAttribsState(vertexAttribs);
//
// render depth if in depthfill mode
//
if (backEnd.depthFill)
{
RB_IterateStagesGeneric( input );
//
// reset polygon offset
//
if ( input->shader->polygonOffset )
{
qglDisable( GL_POLYGON_OFFSET_FILL );
}
return;
}
//
// render shadowmap if in shadowmap mode
//
if (backEnd.viewParms.flags & VPF_SHADOWMAP)
{
if ( input->shader->sort == SS_OPAQUE )
{
RB_RenderShadowmap( input );
}
//
// reset polygon offset
//
if ( input->shader->polygonOffset )
{
qglDisable( GL_POLYGON_OFFSET_FILL );
}
return;
}
//
//
// call shader function
//
RB_IterateStagesGeneric( input );
//
// pshadows!
//
if (glRefConfig.framebufferObject && tess.pshadowBits && tess.shader->sort <= SS_OPAQUE
&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
ProjectPshadowVBOGLSL();
}
//
// now do any dynamic lighting needed
//
if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
if (tess.shader->numUnfoggedPasses == 1 && tess.xstages[0]->glslShaderGroup == tr.lightallShader
&& (tess.xstages[0]->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK) && r_dlightMode->integer)
{
ForwardDlight();
}
else
{
ProjectDlightTexture();
}
}
if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && tess.shader->sort <= SS_OPAQUE
//if ((tr.sunShadows || r_forceSunlight->value > 0.0f) && tess.shader->sort <= SS_OPAQUE
&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader) {
ForwardSunlight();
}
//
// now do fog
//
if ( tess.fogNum && tess.shader->fogPass ) {
RB_FogPass();
}
//
// reset polygon offset
//
if ( input->shader->polygonOffset )
{
qglDisable( GL_POLYGON_OFFSET_FILL );
}
}
/*
** RB_EndSurface
*/
void RB_EndSurface( void ) {
shaderCommands_t *input;
input = &tess;
if (input->numIndexes == 0 || input->numVertexes == 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;
//
// call off to shader specific tess end function
//
tess.currentStageIteratorFunc();
//
// draw debugging stuff
//
if ( r_showtris->integer ) {
DrawTris (input);
}
if ( r_shownormals->integer ) {
DrawNormals (input);
}
// clear shader so we can tell we don't have any unclosed surfaces
tess.numIndexes = 0;
tess.numVertexes = 0;
tess.firstIndex = 0;
tess.multiDrawPrimitives = 0;
GLimp_LogComment( "----------\n" );
}