mirror of
https://github.com/Q3Rally-Team/q3rally.git
synced 2024-11-29 23:22:55 +00:00
3b4f4cdfa9
Some revision messages: Cache servers for each master server in q3_ui, otherwise servers from last updated master for shown for all Internet# sources. Play correct team sounds when in spectator mode and following a player. Check last listener number instead of clc.clientNum in S_AL_HearingThroughEntity so sound work correctly when spectate following a client. (Related to bug 5741.) When in third person, don't play player's sounds as full volume in Base sound system. OpenAL already does this. (Related to bug 5741.) really fix the confusion with game entity and refentity numbers to further reduce confusion, rename constants like MAX_ENTITIES to MAX_REFENTITIES Added Rend2, an alternate renderer. (Bug #4358) Fix restoring fs_game when default.cfg is missing. Fix restoring old fs_game upon leaving a server. Patch by Ensiform. Change more operator commands to require sv_running to be usable. Patch by Ensiform. Fix some "> MAX_*" to be ">= MAX_*". Fix follow command to find clients whose name begins with a number. Fix up "gc" command, make it more like "tell". Based on patch by Ensiform. Add usage messages for gc, tell, vtell, and votell commands. Check player names in gc, tell, vtell, and votell commands. #5799 - Change messagemode text box to display colors like in console input box. Improve "play" command, based on a patch from Ensiform. Check for invalid filename in OpenAL's RegisterSound function. Changed Base sound system to warn not error when sound filename is empty or too long. Remove references to non-existent functions CM_MarkFragments and CM_LerpTag.
1856 lines
47 KiB
C
1856 lines
47 KiB
C
/*
|
|
===========================================================================
|
|
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, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
VectorSet4(color, 1, 1, 1, 1);
|
|
GLSL_SetUniformVec4(sp, TEXTURECOLOR_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'\n", 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, DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
|
|
GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, DLIGHT_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, DLIGHT_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, DLIGHT_UNIFORM_COLOR, vector);
|
|
|
|
vector[0] = origin[0];
|
|
vector[1] = origin[1];
|
|
vector[2] = origin[2];
|
|
vector[3] = scale;
|
|
GLSL_SetUniformVec4(sp, DLIGHT_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, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime);
|
|
}
|
|
|
|
if ( input->fogNum ) {
|
|
vec4_t fogColorMask;
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT);
|
|
|
|
ComputeFogColorMask(pStage, fogColorMask);
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask);
|
|
}
|
|
|
|
{
|
|
vec4_t baseColor;
|
|
vec4_t vertColor;
|
|
|
|
ComputeShaderColors(pStage, baseColor, vertColor);
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, baseColor);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor);
|
|
}
|
|
|
|
if (pStage->alphaGen == AGEN_PORTAL)
|
|
{
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange);
|
|
}
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen);
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen);
|
|
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, dl->color);
|
|
|
|
VectorSet(vector, 0, 0, 0);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, vector);
|
|
|
|
VectorCopy(dl->origin, vector);
|
|
vector[3] = 1.0f;
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, radius);
|
|
|
|
GLSL_SetUniformVec2(sp, GENERIC_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, GENERIC_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, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector);
|
|
|
|
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_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, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime);
|
|
}
|
|
|
|
if ( input->fogNum ) {
|
|
vec4_t fogColorMask;
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT);
|
|
|
|
ComputeFogColorMask(pStage, fogColorMask);
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_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, GENERIC_UNIFORM_BASECOLOR, baseColor);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor);
|
|
}
|
|
|
|
if (pStage->alphaGen == AGEN_PORTAL)
|
|
{
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange);
|
|
}
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen);
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen);
|
|
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, backEnd.refdef.sunCol);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, backEnd.refdef.sunAmbCol);
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, backEnd.refdef.sunDir);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, 9999999999.9f);
|
|
|
|
GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo);
|
|
|
|
GL_State( stageGlState[stage] );
|
|
|
|
GLSL_SetUniformMatrix16(sp, GENERIC_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, GENERIC_UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]);
|
|
GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]);
|
|
GLSL_SetUniformMatrix16(sp, GENERIC_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, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector);
|
|
|
|
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_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, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
|
|
VectorCopy(origin, vector);
|
|
vector[3] = 1.0f;
|
|
GLSL_SetUniformVec4(sp, PSHADOW_UNIFORM_LIGHTORIGIN, vector);
|
|
|
|
VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector);
|
|
GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTFORWARD, vector);
|
|
|
|
VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector);
|
|
GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTRIGHT, vector);
|
|
|
|
VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector);
|
|
GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTUP, vector);
|
|
|
|
GLSL_SetUniformFloat(sp, PSHADOW_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;
|
|
|
|
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, FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
|
|
GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, FOGPASS_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, FOGPASS_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, FOGPASS_UNIFORM_COLOR, color);
|
|
|
|
ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT);
|
|
|
|
GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDISTANCE, fogDistanceVector);
|
|
GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDEPTH, fogDepthVector);
|
|
GLSL_SetUniformFloat(sp, FOGPASS_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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime);
|
|
}
|
|
|
|
if ( input->fogNum ) {
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector);
|
|
GLSL_SetUniformFloat(sp, GENERIC_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];
|
|
unsigned int srcBlendBits;
|
|
//unsigned int dstBlendBits;
|
|
|
|
if ( !pStage2 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
srcBlendBits = pStage2->stateBits & GLS_SRCBLEND_BITS;
|
|
//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, GENERIC_UNIFORM_BASECOLOR, baseColor);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor);
|
|
}
|
|
|
|
if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE)
|
|
{
|
|
vec4_t vec;
|
|
|
|
VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, vec);
|
|
|
|
VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, vec);
|
|
|
|
VectorCopy(backEnd.currentEntity->lightDir, vec);
|
|
vec[3] = 0.0f;
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vec);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, 999999.0f);
|
|
}
|
|
|
|
if (pStage->alphaGen == AGEN_PORTAL)
|
|
{
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange);
|
|
}
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen);
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen);
|
|
|
|
if ( input->fogNum )
|
|
{
|
|
vec4_t fogColorMask;
|
|
|
|
ComputeFogColorMask(pStage, fogColorMask);
|
|
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask);
|
|
}
|
|
|
|
ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix );
|
|
|
|
{
|
|
vec4_t vector;
|
|
VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector);
|
|
|
|
VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]);
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector);
|
|
}
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_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, GENERIC_UNIFORM_TCGEN0VECTOR0, vec);
|
|
VectorCopy(pStage->bundle[0].tcGenVectors[1], vec);
|
|
GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_TCGEN0VECTOR1, vec);
|
|
}
|
|
|
|
GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
|
|
|
|
GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo);
|
|
|
|
//GLSL_SetUniformFloat(sp, GENERIC_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, GENERIC_UNIFORM_TEXTURE1ENV, GL_REPLACE);
|
|
} else {
|
|
GLSL_SetUniformInt(sp, GENERIC_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, GENERIC_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, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
|
|
|
|
GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix);
|
|
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation);
|
|
|
|
GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen);
|
|
if (deformGen != DGEN_NONE)
|
|
{
|
|
GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams);
|
|
GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime);
|
|
}
|
|
|
|
VectorCopy(backEnd.viewParms.or.origin, vector);
|
|
vector[3] = 1.0f;
|
|
GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector);
|
|
GLSL_SetUniformFloat(sp, GENERIC_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" );
|
|
}
|