mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-29 14:17:57 +03:00
5551 lines
154 KiB
C++
5551 lines
154 KiB
C++
![]() |
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 1999-2005 Id Software, Inc.
|
||
|
Copyright (C) 2006-2011 Robert Beckebans <trebor_7@users.sourceforge.net>
|
||
|
|
||
|
This file is part of XreaL source code.
|
||
|
|
||
|
XreaL 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.
|
||
|
|
||
|
XreaL 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 XreaL 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"
|
||
|
#include "gl_shader.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//#define USE_GLSL_OPTIMIZER 1
|
||
|
|
||
|
#if defined(USE_GLSL_OPTIMIZER)
|
||
|
#include "../../libs/glsl-optimizer/src/glsl/glsl_optimizer.h"
|
||
|
|
||
|
static struct glslopt_ctx* s_glslOptimizer;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
=================================================================================
|
||
|
THIS ENTIRE FILE IS BACK END!
|
||
|
|
||
|
This file deals with applying shaders to surface data in the tess struct.
|
||
|
=================================================================================
|
||
|
*/
|
||
|
|
||
|
static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly)
|
||
|
{
|
||
|
char *msg;
|
||
|
static char msgPart[1024];
|
||
|
int maxLength = 0;
|
||
|
int i;
|
||
|
|
||
|
glGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength);
|
||
|
|
||
|
msg = (char *) Com_Allocate(maxLength);
|
||
|
|
||
|
glGetInfoLogARB(object, maxLength, &maxLength, msg);
|
||
|
|
||
|
if(developerOnly)
|
||
|
{
|
||
|
ri.Printf(PRINT_DEVELOPER, "compile log:\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ri.Printf(PRINT_ALL, "compile log:\n");
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < maxLength; i += 1024)
|
||
|
{
|
||
|
Q_strncpyz(msgPart, msg + i, sizeof(msgPart));
|
||
|
|
||
|
if(developerOnly)
|
||
|
ri.Printf(PRINT_DEVELOPER, "%s\n", msgPart);
|
||
|
else
|
||
|
ri.Printf(PRINT_ALL, "%s\n", msgPart);
|
||
|
}
|
||
|
|
||
|
Com_Dealloc(msg);
|
||
|
}
|
||
|
|
||
|
static void GLSL_PrintShaderSource(GLhandleARB object)
|
||
|
{
|
||
|
char *msg;
|
||
|
static char msgPart[1024];
|
||
|
int maxLength = 0;
|
||
|
int i;
|
||
|
|
||
|
glGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength);
|
||
|
|
||
|
msg = (char *) Com_Allocate(maxLength);
|
||
|
|
||
|
glGetShaderSourceARB(object, maxLength, &maxLength, msg);
|
||
|
|
||
|
for(i = 0; i < maxLength; i += 1024)
|
||
|
{
|
||
|
Q_strncpyz(msgPart, msg + i, sizeof(msgPart));
|
||
|
ri.Printf(PRINT_ALL, "%s\n", msgPart);
|
||
|
}
|
||
|
|
||
|
Com_Dealloc(msg);
|
||
|
}
|
||
|
|
||
|
static void GLSL_LoadGPUShader(GLhandleARB program, const char *name, const char *_libs, const char *_compileMacros, GLenum shaderType, qboolean optimize)
|
||
|
{
|
||
|
char filename[MAX_QPATH];
|
||
|
GLcharARB *mainBuffer = NULL;
|
||
|
int mainSize;
|
||
|
GLint compiled;
|
||
|
GLhandleARB shader;
|
||
|
char *token;
|
||
|
|
||
|
int libsSize;
|
||
|
char *libsBuffer; // all libs concatenated
|
||
|
|
||
|
char **libs = (char **) &_libs;
|
||
|
char **compileMacros = (char **) &_compileMacros;
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// load libs
|
||
|
libsSize = 0;
|
||
|
libsBuffer = NULL;
|
||
|
while(1)
|
||
|
{
|
||
|
int libSize;
|
||
|
char *libBuffer; // single extra lib file
|
||
|
|
||
|
token = COM_ParseExt(libs, qfalse);
|
||
|
if(!token[0])
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(shaderType == GL_VERTEX_SHADER_ARB)
|
||
|
{
|
||
|
Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", token);
|
||
|
ri.Printf(PRINT_DEVELOPER, "...loading vertex shader '%s'\n", filename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", token);
|
||
|
}
|
||
|
|
||
|
libSize = ri.FS_ReadFile(filename, (void **)&libBuffer);
|
||
|
if(!libBuffer)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "Couldn't load %s", filename);
|
||
|
}
|
||
|
|
||
|
// append it to the libsBuffer
|
||
|
libsBuffer = (char* ) realloc(libsBuffer, libsSize + libSize);
|
||
|
|
||
|
memset(libsBuffer + libsSize, 0, libSize);
|
||
|
libsSize += libSize;
|
||
|
|
||
|
Q_strcat(libsBuffer, libsSize, libBuffer);
|
||
|
//Q_strncpyz(libsBuffer + libsSize, libBuffer, libSize -1);
|
||
|
|
||
|
|
||
|
|
||
|
ri.FS_FreeFile(libBuffer);
|
||
|
}
|
||
|
|
||
|
// load main() program
|
||
|
if(shaderType == GL_VERTEX_SHADER_ARB)
|
||
|
{
|
||
|
Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name);
|
||
|
ri.Printf(PRINT_DEVELOPER, "...loading vertex main() shader '%s'\n", filename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", name);
|
||
|
ri.Printf(PRINT_DEVELOPER, "...loading fragment main() shader '%s'\n", filename);
|
||
|
}
|
||
|
|
||
|
mainSize = ri.FS_ReadFile(filename, (void **)&mainBuffer);
|
||
|
if(!mainBuffer)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "Couldn't load %s", filename);
|
||
|
}
|
||
|
|
||
|
shader = glCreateShaderObjectARB(shaderType);
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
{
|
||
|
static char bufferExtra[32000];
|
||
|
int sizeExtra;
|
||
|
|
||
|
char *bufferFinal = NULL;
|
||
|
int sizeFinal;
|
||
|
|
||
|
float fbufWidthScale, fbufHeightScale;
|
||
|
float npotWidthScale, npotHeightScale;
|
||
|
|
||
|
Com_Memset(bufferExtra, 0, sizeof(bufferExtra));
|
||
|
|
||
|
// HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones
|
||
|
if(glConfig.driverType == GLDRV_OPENGL3)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#version 130\n");
|
||
|
|
||
|
if(shaderType == GL_VERTEX_SHADER_ARB)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#define attribute in\n");
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#define varying out\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#define varying in\n");
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "out vec4 out_Color;\n");
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#define gl_FragColor out_Color\n");
|
||
|
}
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#define textureCube texture\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#version 120\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
while(1)
|
||
|
{
|
||
|
token = COM_ParseExt(compileMacros, qfalse);
|
||
|
if(!token[0])
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), va("#ifndef %s\n#define %s 1\n#endif\n", token, token));
|
||
|
}
|
||
|
|
||
|
#if defined(COMPAT_Q3A) || defined(COMPAT_ET)
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef COMPAT_Q3A\n#define COMPAT_Q3A 1\n#endif\n");
|
||
|
#endif
|
||
|
|
||
|
// HACK: add some macros to avoid extra uniforms and save speed and code maintenance
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_SpecularExponent\n#define r_SpecularExponent %f\n#endif\n", r_specularExponent->value));
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_SpecularScale\n#define r_SpecularScale %f\n#endif\n", r_specularScale->value));
|
||
|
//Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
// va("#ifndef r_NormalScale\n#define r_NormalScale %f\n#endif\n", r_normalScale->value));
|
||
|
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef M_PI\n#define M_PI 3.14159265358979323846f\n#endif\n");
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), va("#ifndef MAX_SHADOWMAPS\n#define MAX_SHADOWMAPS %i\n#endif\n", MAX_SHADOWMAPS));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef deformGen_t\n"
|
||
|
"#define deformGen_t\n"
|
||
|
"#define DGEN_WAVE_SIN %i\n"
|
||
|
"#define DGEN_WAVE_SQUARE %i\n"
|
||
|
"#define DGEN_WAVE_TRIANGLE %i\n"
|
||
|
"#define DGEN_WAVE_SAWTOOTH %i\n"
|
||
|
"#define DGEN_WAVE_INVERSE_SAWTOOTH %i\n"
|
||
|
"#define DGEN_BULGE %i\n"
|
||
|
"#define DGEN_MOVE %i\n"
|
||
|
"#endif\n",
|
||
|
DGEN_WAVE_SIN,
|
||
|
DGEN_WAVE_SQUARE,
|
||
|
DGEN_WAVE_TRIANGLE,
|
||
|
DGEN_WAVE_SAWTOOTH,
|
||
|
DGEN_WAVE_INVERSE_SAWTOOTH,
|
||
|
DGEN_BULGE,
|
||
|
DGEN_MOVE));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef colorGen_t\n"
|
||
|
"#define colorGen_t\n"
|
||
|
"#define CGEN_VERTEX %i\n"
|
||
|
"#define CGEN_ONE_MINUS_VERTEX %i\n"
|
||
|
"#endif\n",
|
||
|
CGEN_VERTEX,
|
||
|
CGEN_ONE_MINUS_VERTEX));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef alphaGen_t\n"
|
||
|
"#define alphaGen_t\n"
|
||
|
"#define AGEN_VERTEX %i\n"
|
||
|
"#define AGEN_ONE_MINUS_VERTEX %i\n"
|
||
|
"#endif\n",
|
||
|
AGEN_VERTEX,
|
||
|
AGEN_ONE_MINUS_VERTEX));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef alphaTest_t\n"
|
||
|
"#define alphaTest_t\n"
|
||
|
"#define ATEST_GT_0 %i\n"
|
||
|
"#define ATEST_LT_128 %i\n"
|
||
|
"#define ATEST_GE_128 %i\n"
|
||
|
"#endif\n",
|
||
|
ATEST_GT_0,
|
||
|
ATEST_LT_128,
|
||
|
ATEST_GE_128));
|
||
|
|
||
|
fbufWidthScale = Q_rsqrt((float)glConfig.vidWidth);
|
||
|
fbufHeightScale = Q_rsqrt((float)glConfig.vidHeight);
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale));
|
||
|
|
||
|
if(glConfig2.textureNPOTAvailable)
|
||
|
{
|
||
|
npotWidthScale = 1;
|
||
|
npotHeightScale = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
npotWidthScale = (float)glConfig.vidWidth / (float)NearestPowerOfTwo(glConfig.vidWidth);
|
||
|
npotHeightScale = (float)glConfig.vidHeight / (float)NearestPowerOfTwo(glConfig.vidHeight);
|
||
|
}
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_NPOTScale\n#define r_NPOTScale vec2(%f, %f)\n#endif\n", npotWidthScale, npotHeightScale));
|
||
|
|
||
|
if(glConfig.driverType == GLDRV_MESA)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GLDRV_MESA\n#define GLDRV_MESA 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(glConfig.hardwareType == GLHW_ATI)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GLHW_ATI\n#define GLHW_ATI 1\n#endif\n");
|
||
|
}
|
||
|
else if(glConfig.hardwareType == GLHW_ATI_DX10)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GLHW_ATI_DX10\n#define GLHW_ATI_DX10 1\n#endif\n");
|
||
|
}
|
||
|
else if(glConfig.hardwareType == GLHW_NV_DX10)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GLHW_NV_DX10\n#define GLHW_NV_DX10 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_shadows->integer >= SHADOWING_ESM16 && glConfig2.textureFloatAvailable && glConfig2.framebufferObjectAvailable)
|
||
|
{
|
||
|
if(r_shadows->integer == SHADOWING_EVSM32)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef ESM\n#define ESM 1\n#endif\n");
|
||
|
|
||
|
if(r_debugShadowMaps->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef DEBUG_EVSM\n#define DEBUG_EVSM %i\n#endif\n", r_debugShadowMaps->integer));
|
||
|
}
|
||
|
|
||
|
if(r_lightBleedReduction->value)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_LightBleedReduction\n#define r_LightBleedReduction %f\n#endif\n",
|
||
|
r_lightBleedReduction->value));
|
||
|
}
|
||
|
|
||
|
if(r_overDarkeningFactor->value)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_OverDarkeningFactor\n#define r_OverDarkeningFactor %f\n#endif\n",
|
||
|
r_overDarkeningFactor->value));
|
||
|
}
|
||
|
|
||
|
if(r_shadowMapDepthScale->value)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_ShadowMapDepthScale\n#define r_ShadowMapDepthScale %f\n#endif\n",
|
||
|
r_shadowMapDepthScale->value));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef VSM\n#define VSM 1\n#endif\n");
|
||
|
|
||
|
if(glConfig.hardwareType == GLHW_ATI)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef VSM_CLAMP\n#define VSM_CLAMP 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if((glConfig.hardwareType == GLHW_NV_DX10 || glConfig.hardwareType == GLHW_ATI_DX10) && r_shadows->integer == SHADOWING_VSM32)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef VSM_EPSILON\n#define VSM_EPSILON 0.000001\n#endif\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef VSM_EPSILON\n#define VSM_EPSILON 0.0001\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_debugShadowMaps->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef DEBUG_VSM\n#define DEBUG_VSM %i\n#endif\n", r_debugShadowMaps->integer));
|
||
|
}
|
||
|
|
||
|
if(r_lightBleedReduction->value)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_LightBleedReduction\n#define r_LightBleedReduction %f\n#endif\n",
|
||
|
r_lightBleedReduction->value));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(r_softShadows->integer == 1)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCF_2X2\n#define PCF_2X2 1\n#endif\n");
|
||
|
}
|
||
|
else if(r_softShadows->integer == 2)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCF_3X3\n#define PCF_3X3 1\n#endif\n");
|
||
|
}
|
||
|
else if(r_softShadows->integer == 3)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCF_4X4\n#define PCF_4X4 1\n#endif\n");
|
||
|
}
|
||
|
else if(r_softShadows->integer == 4)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCF_5X5\n#define PCF_5X5 1\n#endif\n");
|
||
|
}
|
||
|
else if(r_softShadows->integer == 5)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCF_6X6\n#define PCF_6X6 1\n#endif\n");
|
||
|
}
|
||
|
else if(r_softShadows->integer == 6)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef PCSS\n#define PCSS 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_parallelShadowSplits->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_ParallelShadowSplits_%i\n#define r_ParallelShadowSplits_%i\n#endif\n", r_parallelShadowSplits->integer, r_parallelShadowSplits->integer));
|
||
|
}
|
||
|
|
||
|
if(r_showParallelShadowSplits->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_ShowParallelShadowSplits\n#define r_ShowParallelShadowSplits 1\n#endif\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if(r_hdrRendering->integer && glConfig2.framebufferObjectAvailable && glConfig2.textureFloatAvailable)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_HDRRendering\n#define r_HDRRendering 1\n#endif\n");
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_HDRContrastThreshold\n#define r_HDRContrastThreshold %f\n#endif\n",
|
||
|
r_hdrContrastThreshold->value));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_HDRContrastOffset\n#define r_HDRContrastOffset %f\n#endif\n",
|
||
|
r_hdrContrastOffset->value));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_HDRToneMappingOperator\n#define r_HDRToneMappingOperator_%i\n#endif\n",
|
||
|
r_hdrToneMappingOperator->integer));
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_HDRGamma\n#define r_HDRGamma %f\n#endif\n",
|
||
|
r_hdrGamma->value));
|
||
|
}
|
||
|
|
||
|
if(r_precomputedLighting->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
"#ifndef r_precomputedLighting\n#define r_precomputedLighting 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_heatHazeFix->integer && glConfig2.framebufferBlitAvailable && glConfig.hardwareType != GLHW_ATI && glConfig.hardwareType != GLHW_ATI_DX10 && glConfig.driverType != GLDRV_MESA)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_heatHazeFix\n#define r_heatHazeFix 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_showLightMaps->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_showLightMaps\n#define r_showLightMaps 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_showDeluxeMaps->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_showDeluxeMaps\n#define r_showDeluxeMaps 1\n#endif\n");
|
||
|
}
|
||
|
#ifdef EXPERIMENTAL
|
||
|
if(r_screenSpaceAmbientOcclusion->integer)
|
||
|
{
|
||
|
int i;
|
||
|
static vec3_t jitter[32];
|
||
|
static qboolean jitterInit = qfalse;
|
||
|
|
||
|
if(!jitterInit)
|
||
|
{
|
||
|
for(i = 0; i < 32; i++)
|
||
|
{
|
||
|
float *jit = &jitter[i][0];
|
||
|
|
||
|
float rad = crandom() * 1024.0f; // FIXME radius;
|
||
|
float a = crandom() * M_PI * 2;
|
||
|
float b = crandom() * M_PI * 2;
|
||
|
|
||
|
jit[0] = rad * sin(a) * cos(b);
|
||
|
jit[1] = rad * sin(a) * sin(b);
|
||
|
jit[2] = rad * cos(a);
|
||
|
}
|
||
|
|
||
|
jitterInit = qtrue;
|
||
|
}
|
||
|
|
||
|
// TODO
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_VertexSkinning\n#define r_VertexSkinning 1\n#endif\n");
|
||
|
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef MAX_GLSL_BONES\n#define MAX_GLSL_BONES %i\n#endif\n", glConfig2.maxVertexSkinningBones));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if(glConfig2.drawBuffersAvailable && glConfig2.maxDrawBuffers >= 4)
|
||
|
{
|
||
|
//Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GL_ARB_draw_buffers\n#define GL_ARB_draw_buffers 1\n#endif\n");
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#extension GL_ARB_draw_buffers : enable\n");
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
if(r_normalMapping->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_NormalMapping\n#define r_NormalMapping 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if( /* TODO: check for shader model 3 hardware && */ r_normalMapping->integer && r_parallaxMapping->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_ParallaxMapping\n#define r_ParallaxMapping 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
if(r_wrapAroundLighting->value)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra),
|
||
|
va("#ifndef r_WrapAroundLighting\n#define r_WrapAroundLighting %f\n#endif\n",
|
||
|
r_wrapAroundLighting->value));
|
||
|
}
|
||
|
|
||
|
if(r_halfLambertLighting->integer)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef r_halfLambertLighting\n#define r_halfLambertLighting 1\n#endif\n");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if(glConfig2.textureFloatAvailable)
|
||
|
{
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#ifndef GL_ARB_texture_float\n#define GL_ARB_texture_float 1\n#endif\n");
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
// OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line
|
||
|
// so we have to reset the line counting
|
||
|
Q_strcat(bufferExtra, sizeof(bufferExtra), "#line 0\n");
|
||
|
|
||
|
sizeExtra = strlen(bufferExtra);
|
||
|
sizeFinal = sizeExtra + mainSize + libsSize;
|
||
|
|
||
|
//ri.Printf(PRINT_ALL, "GLSL extra: %s\n", bufferExtra);
|
||
|
|
||
|
bufferFinal = (char *) ri.Malloc(sizeFinal);
|
||
|
|
||
|
strcpy(bufferFinal, bufferExtra);
|
||
|
|
||
|
if(libsSize > 0)
|
||
|
{
|
||
|
Q_strcat(bufferFinal, sizeFinal, libsBuffer);
|
||
|
}
|
||
|
|
||
|
Q_strcat(bufferFinal, sizeFinal, mainBuffer);
|
||
|
|
||
|
#if 0
|
||
|
{
|
||
|
static char msgPart[1024];
|
||
|
int i;
|
||
|
ri.Printf(PRINT_WARNING, "----------------------------------------------------------\n", filename);
|
||
|
ri.Printf(PRINT_WARNING, "CONCATENATED shader '%s' ----------\n", filename);
|
||
|
ri.Printf(PRINT_WARNING, " BEGIN ---------------------------------------------------\n", filename);
|
||
|
|
||
|
for(i = 0; i < sizeFinal; i += 1024)
|
||
|
{
|
||
|
Q_strncpyz(msgPart, bufferFinal + i, sizeof(msgPart));
|
||
|
ri.Printf(PRINT_ALL, "%s", msgPart);
|
||
|
}
|
||
|
|
||
|
ri.Printf(PRINT_WARNING, " END-- ---------------------------------------------------\n", filename);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if defined(USE_GLSL_OPTIMIZER)
|
||
|
if(glConfig.driverType != GLDRV_OPENGL3 && optimize)
|
||
|
{
|
||
|
static char msgPart[1024];
|
||
|
int length = 0;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
glslopt_shader_type glsloptShaderType;
|
||
|
|
||
|
if(shaderType == GL_FRAGMENT_SHADER_ARB)
|
||
|
glsloptShaderType = kGlslOptShaderFragment;
|
||
|
else
|
||
|
glsloptShaderType = kGlslOptShaderVertex;
|
||
|
|
||
|
glslopt_shader* shaderOptimized = glslopt_optimize(s_glslOptimizer,
|
||
|
glsloptShaderType, bufferFinal, 0);
|
||
|
|
||
|
if(glslopt_get_status(shaderOptimized))
|
||
|
{
|
||
|
const char* newSource = glslopt_get_output(shaderOptimized);
|
||
|
|
||
|
ri.Printf(PRINT_WARNING, "----------------------------------------------------------\n", filename);
|
||
|
ri.Printf(PRINT_WARNING, "OPTIMIZED shader '%s' ----------\n", filename);
|
||
|
ri.Printf(PRINT_WARNING, " BEGIN ---------------------------------------------------\n", filename);
|
||
|
|
||
|
length = strlen(newSource);
|
||
|
for(i = 0; i < length; i += 1024)
|
||
|
{
|
||
|
Q_strncpyz(msgPart, newSource + i, sizeof(msgPart));
|
||
|
ri.Printf(PRINT_ALL, "%s\n", msgPart);
|
||
|
}
|
||
|
|
||
|
ri.Printf(PRINT_WARNING, " END-- ---------------------------------------------------\n", filename);
|
||
|
|
||
|
glShaderSourceARB(shader, 1, (const GLcharARB **)&newSource, &length);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const char* errorLog = glslopt_get_log(shaderOptimized);
|
||
|
|
||
|
//ri.Printf(PRINT_WARNING, "Couldn't optimize '%s'", filename);
|
||
|
|
||
|
length = strlen(errorLog);
|
||
|
for(i = 0; i < length; i += 1024)
|
||
|
{
|
||
|
Q_strncpyz(msgPart, errorLog + i, sizeof(msgPart));
|
||
|
ri.Printf(PRINT_ALL, "%s\n", msgPart);
|
||
|
}
|
||
|
|
||
|
ri.Error(ERR_FATAL, "Couldn't optimize %s", filename);
|
||
|
}
|
||
|
|
||
|
glslopt_shader_delete(shaderOptimized);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glShaderSourceARB(shader, 1, (const GLcharARB **)&bufferFinal, &sizeFinal);
|
||
|
}
|
||
|
#else
|
||
|
glShaderSourceARB(shader, 1, (const GLcharARB **)&bufferFinal, &sizeFinal);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
ri.Free(bufferFinal);
|
||
|
}
|
||
|
|
||
|
// compile shader
|
||
|
glCompileShaderARB(shader);
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// check if shader compiled
|
||
|
glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
|
||
|
if(!compiled)
|
||
|
{
|
||
|
GLSL_PrintShaderSource(shader);
|
||
|
GLSL_PrintInfoLog(shader, qfalse);
|
||
|
ri.Error(ERR_DROP, "Couldn't compile %s", filename);
|
||
|
ri.FS_FreeFile(mainBuffer);
|
||
|
free(libsBuffer);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GLSL_PrintInfoLog(shader, qtrue);
|
||
|
//ri.Printf(PRINT_ALL, "%s\n", GLSL_PrintShaderSource(shader));
|
||
|
|
||
|
// attach shader to program
|
||
|
glAttachObjectARB(program, shader);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// delete shader, no longer needed
|
||
|
glDeleteObjectARB(shader);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
ri.FS_FreeFile(mainBuffer);
|
||
|
free(libsBuffer);
|
||
|
}
|
||
|
|
||
|
static void GLSL_LinkProgram(GLhandleARB program)
|
||
|
{
|
||
|
GLint linked;
|
||
|
|
||
|
glLinkProgramARB(program);
|
||
|
|
||
|
glGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked);
|
||
|
if(!linked)
|
||
|
{
|
||
|
GLSL_PrintInfoLog(program, qfalse);
|
||
|
ri.Error(ERR_DROP, "%s\nshaders failed to link");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GLSL_ValidateProgram(GLhandleARB program)
|
||
|
{
|
||
|
GLint validated;
|
||
|
|
||
|
glValidateProgramARB(program);
|
||
|
|
||
|
glGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated);
|
||
|
if(!validated)
|
||
|
{
|
||
|
GLSL_PrintInfoLog(program, qfalse);
|
||
|
ri.Error(ERR_DROP, "%s\nshaders failed to validate");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GLSL_ShowProgramUniforms(GLhandleARB program)
|
||
|
{
|
||
|
int i, count, size;
|
||
|
GLenum type;
|
||
|
char uniformName[1000];
|
||
|
|
||
|
// install the executables in the program object as part of current state.
|
||
|
glUseProgramObjectARB(program);
|
||
|
|
||
|
// check for GL Errors
|
||
|
|
||
|
// query the number of active uniforms
|
||
|
glGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count);
|
||
|
|
||
|
// Loop over each of the active uniforms, and set their value
|
||
|
for(i = 0; i < count; i++)
|
||
|
{
|
||
|
glGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName);
|
||
|
|
||
|
ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName);
|
||
|
}
|
||
|
|
||
|
glUseProgramObjectARB(0);
|
||
|
}
|
||
|
|
||
|
static void GLSL_BindAttribLocations(GLhandleARB program, uint32_t attribs)
|
||
|
{
|
||
|
if(attribs & ATTR_POSITION)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_POSITION, "attr_Position");
|
||
|
|
||
|
if(attribs & ATTR_TEXCOORD)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_TEXCOORD0, "attr_TexCoord0");
|
||
|
|
||
|
if(attribs & ATTR_LIGHTCOORD)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_TEXCOORD1, "attr_TexCoord1");
|
||
|
|
||
|
// if(attribs & ATTR_TEXCOORD2)
|
||
|
// glBindAttribLocationARB(program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2");
|
||
|
|
||
|
// if(attribs & ATTR_TEXCOORD3)
|
||
|
// glBindAttribLocationARB(program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3");
|
||
|
|
||
|
if(attribs & ATTR_TANGENT)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_TANGENT, "attr_Tangent");
|
||
|
|
||
|
if(attribs & ATTR_BINORMAL)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_BINORMAL, "attr_Binormal");
|
||
|
|
||
|
if(attribs & ATTR_NORMAL)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_NORMAL, "attr_Normal");
|
||
|
|
||
|
if(attribs & ATTR_COLOR)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_COLOR, "attr_Color");
|
||
|
|
||
|
#if !defined(COMPAT_Q3A) && !defined(COMPAT_ET)
|
||
|
if(attribs & ATTR_PAINTCOLOR)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor");
|
||
|
|
||
|
if(attribs & ATTR_LIGHTDIRECTION)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection");
|
||
|
#endif
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable)
|
||
|
{
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_BONE_INDEXES, "attr_BoneIndexes");
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_BONE_WEIGHTS, "attr_BoneWeights");
|
||
|
}
|
||
|
|
||
|
if(attribs & ATTR_POSITION2)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_POSITION2, "attr_Position2");
|
||
|
|
||
|
if(attribs & ATTR_TANGENT2)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_TANGENT2, "attr_Tangent2");
|
||
|
|
||
|
if(attribs & ATTR_BINORMAL2)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_BINORMAL2, "attr_Binormal2");
|
||
|
|
||
|
if(attribs & ATTR_NORMAL2)
|
||
|
glBindAttribLocationARB(program, ATTR_INDEX_NORMAL2, "attr_Normal2");
|
||
|
}
|
||
|
|
||
|
static void GLSL_InitGPUShader(shaderProgram_t * program, const char *name, int attribs, qboolean fragmentShader, qboolean optimize)
|
||
|
{
|
||
|
ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n");
|
||
|
|
||
|
if(strlen(name) >= MAX_QPATH)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "GLSL_InitGPUShader: \"%s\" is too long\n", name);
|
||
|
}
|
||
|
|
||
|
Q_strncpyz(program->name, name, sizeof(program->name));
|
||
|
|
||
|
program->program = glCreateProgramObjectARB();
|
||
|
program->attribs = attribs;
|
||
|
|
||
|
GLSL_LoadGPUShader(program->program, name, "", "", GL_VERTEX_SHADER_ARB, optimize);
|
||
|
GLSL_LoadGPUShader(program->program, name, "", "", GL_FRAGMENT_SHADER_ARB, optimize);
|
||
|
|
||
|
GLSL_BindAttribLocations(program->program, attribs);
|
||
|
GLSL_LinkProgram(program->program);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
static void GLSL_InitGPUShader2(shaderProgram_t * program,
|
||
|
const char *vertexMainShader,
|
||
|
const char *fragmentMainShader,
|
||
|
const char *vertexLibShaders,
|
||
|
const char *fragmentLibShaders,
|
||
|
int attribs,
|
||
|
qboolean optimize)
|
||
|
{
|
||
|
ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n");
|
||
|
|
||
|
if(strlen(vertexMainShader) >= MAX_QPATH)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long\n", vertexMainShader);
|
||
|
}
|
||
|
|
||
|
if(strlen(fragmentMainShader) >= MAX_QPATH)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long\n", fragmentMainShader);
|
||
|
}
|
||
|
|
||
|
Q_strncpyz(program->name, fragmentMainShader, sizeof(program->name));
|
||
|
|
||
|
program->program = glCreateProgramObjectARB();
|
||
|
program->attribs = attribs;
|
||
|
|
||
|
GLSL_LoadGPUShader(program->program, vertexMainShader, vertexLibShaders, "", GL_VERTEX_SHADER_ARB, optimize);
|
||
|
GLSL_LoadGPUShader(program->program, fragmentMainShader, fragmentLibShaders, "", GL_FRAGMENT_SHADER_ARB, optimize);
|
||
|
|
||
|
GLSL_BindAttribLocations(program->program, attribs);
|
||
|
GLSL_LinkProgram(program->program);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
void GLSL_InitGPUShader3(shaderProgram_t * program,
|
||
|
const char *vertexMainShader,
|
||
|
const char *fragmentMainShader,
|
||
|
const char *vertexLibShaders,
|
||
|
const char *fragmentLibShaders,
|
||
|
const char *compileMacros,
|
||
|
int attribs,
|
||
|
qboolean optimize)
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n");
|
||
|
|
||
|
if(strlen(vertexMainShader) >= MAX_QPATH)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "GLSL_InitGPUShader3: \"%s\" is too long\n", vertexMainShader);
|
||
|
}
|
||
|
|
||
|
if(strlen(fragmentMainShader) >= MAX_QPATH)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "GLSL_InitGPUShader3: \"%s\" is too long\n", fragmentMainShader);
|
||
|
}
|
||
|
|
||
|
Q_strncpyz(program->name, fragmentMainShader, sizeof(program->name));
|
||
|
|
||
|
len = strlen(compileMacros) + 1;
|
||
|
program->compileMacros = (char *) ri.Hunk_Alloc(sizeof(char) * len, h_low);
|
||
|
Q_strncpyz(program->compileMacros, compileMacros, len);
|
||
|
|
||
|
program->program = glCreateProgramObjectARB();
|
||
|
program->attribs = attribs;
|
||
|
|
||
|
GLSL_LoadGPUShader(program->program, vertexMainShader, vertexLibShaders, compileMacros, GL_VERTEX_SHADER_ARB, optimize);
|
||
|
GLSL_LoadGPUShader(program->program, fragmentMainShader, fragmentLibShaders, compileMacros, GL_FRAGMENT_SHADER_ARB, optimize);
|
||
|
|
||
|
GLSL_BindAttribLocations(program->program, attribs);
|
||
|
GLSL_LinkProgram(program->program);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void GLSL_InitGPUShaders(void)
|
||
|
{
|
||
|
int startTime, endTime;
|
||
|
|
||
|
ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n");
|
||
|
|
||
|
// make sure the render thread is stopped
|
||
|
R_SyncRenderThread();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
#if defined(USE_GLSL_OPTIMIZER)
|
||
|
s_glslOptimizer = glslopt_initialize();
|
||
|
#endif
|
||
|
|
||
|
startTime = ri.Milliseconds();
|
||
|
|
||
|
// single texture rendering
|
||
|
gl_genericShader = new GLShader_generic();
|
||
|
|
||
|
// simple vertex color shading for entities
|
||
|
gl_vertexLightingShader_DBS_entity = new GLShader_vertexLighting_DBS_entity();
|
||
|
|
||
|
// simple vertex color shading for the world
|
||
|
gl_vertexLightingShader_DBS_world = new GLShader_vertexLighting_DBS_world();
|
||
|
|
||
|
// standard light mapping
|
||
|
gl_lightMappingShader = new GLShader_lightMapping();
|
||
|
|
||
|
// geometric-buffer fill rendering with diffuse + bump + specular
|
||
|
if(DS_STANDARD_ENABLED())
|
||
|
{
|
||
|
// G-Buffer construction
|
||
|
gl_geometricFillShader = new GLShader_geometricFill();
|
||
|
|
||
|
// deferred omni-directional lighting post process effect
|
||
|
gl_deferredLightingShader_omniXYZ = new GLShader_deferredLighting_omniXYZ();
|
||
|
|
||
|
gl_deferredLightingShader_projXYZ = new GLShader_deferredLighting_projXYZ();
|
||
|
|
||
|
gl_deferredLightingShader_directionalSun = new GLShader_deferredLighting_directionalSun();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// omni-directional specular bump mapping ( Doom3 style )
|
||
|
gl_forwardLightingShader_omniXYZ = new GLShader_forwardLighting_omniXYZ();
|
||
|
|
||
|
// projective lighting ( Doom3 style )
|
||
|
gl_forwardLightingShader_projXYZ = new GLShader_forwardLighting_projXYZ();
|
||
|
|
||
|
// directional sun lighting ( Doom3 style )
|
||
|
gl_forwardLightingShader_directionalSun = new GLShader_forwardLighting_directionalSun();
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
// depth to color encoding
|
||
|
GLSL_InitGPUShader(&tr.depthToColorShader, "depthToColor", ATTR_POSITION, qtrue, qtrue);
|
||
|
|
||
|
tr.depthToColorShader.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.depthToColorShader.program, "u_ModelViewProjectionMatrix");
|
||
|
if(glConfig2.vboVertexSkinningAvailable)
|
||
|
{
|
||
|
tr.depthToColorShader.u_VertexSkinning = glGetUniformLocationARB(tr.depthToColorShader.program, "u_VertexSkinning");
|
||
|
tr.depthToColorShader.u_BoneMatrix = glGetUniformLocationARB(tr.depthToColorShader.program, "u_BoneMatrix");
|
||
|
}
|
||
|
|
||
|
glUseProgramObjectARB(tr.depthToColorShader.program);
|
||
|
//glUniform1iARB(tr.depthToColorShader.u_ColorMap, 0);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.depthToColorShader.program);
|
||
|
GLSL_ShowProgramUniforms(tr.depthToColorShader.program);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
|
||
|
// shadowmap distance compression
|
||
|
gl_shadowFillShader = new GLShader_shadowFill();
|
||
|
|
||
|
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
#ifdef VOLUMETRIC_LIGHTING
|
||
|
// volumetric lighting
|
||
|
GLSL_InitGPUShader(&tr.lightVolumeShader_omni, "lightVolume_omni", ATTR_POSITION, qtrue);
|
||
|
|
||
|
tr.lightVolumeShader_omni.u_DepthMap =
|
||
|
glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_DepthMap");
|
||
|
tr.lightVolumeShader_omni.u_AttenuationMapXY =
|
||
|
glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_AttenuationMapXY");
|
||
|
tr.lightVolumeShader_omni.u_AttenuationMapZ =
|
||
|
glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_AttenuationMapZ");
|
||
|
tr.lightVolumeShader_omni.u_ShadowMap = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_ShadowMap");
|
||
|
tr.lightVolumeShader_omni.u_ViewOrigin = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_ViewOrigin");
|
||
|
tr.lightVolumeShader_omni.u_LightOrigin = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_LightOrigin");
|
||
|
tr.lightVolumeShader_omni.u_LightColor = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_LightColor");
|
||
|
tr.lightVolumeShader_omni.u_LightRadius = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_LightRadius");
|
||
|
tr.lightVolumeShader_omni.u_LightScale = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_LightScale");
|
||
|
tr.lightVolumeShader_omni.u_LightAttenuationMatrix =
|
||
|
glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_LightAttenuationMatrix");
|
||
|
tr.lightVolumeShader_omni.u_ShadowCompare = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_ShadowCompare");
|
||
|
tr.lightVolumeShader_omni.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_ModelViewProjectionMatrix");
|
||
|
tr.lightVolumeShader_omni.u_UnprojectMatrix = glGetUniformLocationARB(tr.lightVolumeShader_omni.program, "u_UnprojectMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.lightVolumeShader_omni.program);
|
||
|
glUniform1iARB(tr.lightVolumeShader_omni.u_DepthMap, 0);
|
||
|
glUniform1iARB(tr.lightVolumeShader_omni.u_AttenuationMapXY, 1);
|
||
|
glUniform1iARB(tr.lightVolumeShader_omni.u_AttenuationMapZ, 2);
|
||
|
glUniform1iARB(tr.lightVolumeShader_omni.u_ShadowMap, 3);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.lightVolumeShader_omni.program);
|
||
|
GLSL_ShowProgramUniforms(tr.lightVolumeShader_omni.program);
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
|
||
|
// UT3 style player shadowing
|
||
|
GLSL_InitGPUShader(&tr.deferredShadowingShader_proj, "deferredShadowing_proj", ATTR_POSITION, qtrue, qtrue);
|
||
|
|
||
|
tr.deferredShadowingShader_proj.u_DepthMap =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_DepthMap");
|
||
|
tr.deferredShadowingShader_proj.u_AttenuationMapXY =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_AttenuationMapXY");
|
||
|
tr.deferredShadowingShader_proj.u_AttenuationMapZ =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_AttenuationMapZ");
|
||
|
tr.deferredShadowingShader_proj.u_ShadowMap =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_ShadowMap");
|
||
|
tr.deferredShadowingShader_proj.u_LightOrigin =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_LightOrigin");
|
||
|
tr.deferredShadowingShader_proj.u_LightColor =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_LightColor");
|
||
|
tr.deferredShadowingShader_proj.u_LightRadius =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_LightRadius");
|
||
|
tr.deferredShadowingShader_proj.u_LightAttenuationMatrix =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_LightAttenuationMatrix");
|
||
|
tr.deferredShadowingShader_proj.u_ShadowMatrix =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_ShadowMatrix");
|
||
|
tr.deferredShadowingShader_proj.u_ShadowCompare =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_ShadowCompare");
|
||
|
tr.deferredShadowingShader_proj.u_PortalClipping =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_PortalClipping");
|
||
|
tr.deferredShadowingShader_proj.u_PortalPlane =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_PortalPlane");
|
||
|
tr.deferredShadowingShader_proj.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_ModelViewProjectionMatrix");
|
||
|
tr.deferredShadowingShader_proj.u_UnprojectMatrix =
|
||
|
glGetUniformLocationARB(tr.deferredShadowingShader_proj.program, "u_UnprojectMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.deferredShadowingShader_proj.program);
|
||
|
glUniform1iARB(tr.deferredShadowingShader_proj.u_DepthMap, 0);
|
||
|
glUniform1iARB(tr.deferredShadowingShader_proj.u_AttenuationMapXY, 1);
|
||
|
glUniform1iARB(tr.deferredShadowingShader_proj.u_AttenuationMapZ, 2);
|
||
|
glUniform1iARB(tr.deferredShadowingShader_proj.u_ShadowMap, 3);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.deferredShadowingShader_proj.program);
|
||
|
GLSL_ShowProgramUniforms(tr.deferredShadowingShader_proj.program);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
// bumped cubemap reflection for abitrary polygons ( EMBM )
|
||
|
gl_reflectionShader = new GLShader_reflection();
|
||
|
|
||
|
// skybox drawing for abitrary polygons
|
||
|
gl_skyboxShader = new GLShader_skybox();
|
||
|
|
||
|
// Q3A volumetric fog
|
||
|
gl_fogQuake3Shader = new GLShader_fogQuake3();
|
||
|
|
||
|
// global fog post process effect
|
||
|
gl_fogGlobalShader = new GLShader_fogGlobal();
|
||
|
|
||
|
// heatHaze post process effect
|
||
|
gl_heatHazeShader = new GLShader_heatHaze();
|
||
|
|
||
|
// screen post process effect
|
||
|
gl_screenShader = new GLShader_screen();
|
||
|
|
||
|
// portal process effect
|
||
|
gl_portalShader = new GLShader_portal();
|
||
|
|
||
|
// HDR -> LDR tone mapping
|
||
|
gl_toneMappingShader = new GLShader_toneMapping();
|
||
|
|
||
|
// LDR bright pass filter
|
||
|
gl_contrastShader = new GLShader_contrast();
|
||
|
|
||
|
// camera post process effect
|
||
|
gl_cameraEffectsShader = new GLShader_cameraEffects();
|
||
|
|
||
|
// gaussian blur
|
||
|
gl_blurXShader = new GLShader_blurX();
|
||
|
|
||
|
gl_blurYShader = new GLShader_blurY();
|
||
|
|
||
|
// debug utils
|
||
|
gl_debugShadowMapShader = new GLShader_debugShadowMap();
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
// liquid post process effect
|
||
|
GLSL_InitGPUShader(&tr.liquidShader, "liquid",
|
||
|
ATTR_POSITION | ATTR_TEXCOORD | ATTR_TANGENT | ATTR_BINORMAL | ATTR_NORMAL | ATTR_COLOR
|
||
|
|
||
|
#if !defined(COMPAT_Q3A) && !defined(COMPAT_ET)
|
||
|
| ATTR_LIGHTDIRECTION
|
||
|
#endif
|
||
|
, qtrue, qtrue);
|
||
|
|
||
|
tr.liquidShader.u_CurrentMap = glGetUniformLocationARB(tr.liquidShader.program, "u_CurrentMap");
|
||
|
tr.liquidShader.u_PortalMap = glGetUniformLocationARB(tr.liquidShader.program, "u_PortalMap");
|
||
|
tr.liquidShader.u_DepthMap = glGetUniformLocationARB(tr.liquidShader.program, "u_DepthMap");
|
||
|
tr.liquidShader.u_NormalMap = glGetUniformLocationARB(tr.liquidShader.program, "u_NormalMap");
|
||
|
tr.liquidShader.u_NormalTextureMatrix = glGetUniformLocationARB(tr.liquidShader.program, "u_NormalTextureMatrix");
|
||
|
tr.liquidShader.u_ViewOrigin = glGetUniformLocationARB(tr.liquidShader.program, "u_ViewOrigin");
|
||
|
tr.liquidShader.u_RefractionIndex = glGetUniformLocationARB(tr.liquidShader.program, "u_RefractionIndex");
|
||
|
tr.liquidShader.u_FresnelPower = glGetUniformLocationARB(tr.liquidShader.program, "u_FresnelPower");
|
||
|
tr.liquidShader.u_FresnelScale = glGetUniformLocationARB(tr.liquidShader.program, "u_FresnelScale");
|
||
|
tr.liquidShader.u_FresnelBias = glGetUniformLocationARB(tr.liquidShader.program, "u_FresnelBias");
|
||
|
tr.liquidShader.u_NormalScale = glGetUniformLocationARB(tr.liquidShader.program, "u_NormalScale");
|
||
|
tr.liquidShader.u_FogDensity = glGetUniformLocationARB(tr.liquidShader.program, "u_FogDensity");
|
||
|
tr.liquidShader.u_FogColor = glGetUniformLocationARB(tr.liquidShader.program, "u_FogColor");
|
||
|
tr.liquidShader.u_ModelMatrix = glGetUniformLocationARB(tr.liquidShader.program, "u_ModelMatrix");
|
||
|
tr.liquidShader.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.liquidShader.program, "u_ModelViewProjectionMatrix");
|
||
|
tr.liquidShader.u_UnprojectMatrix = glGetUniformLocationARB(tr.liquidShader.program, "u_UnprojectMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.liquidShader.program);
|
||
|
glUniform1iARB(tr.liquidShader.u_CurrentMap, 0);
|
||
|
glUniform1iARB(tr.liquidShader.u_PortalMap, 1);
|
||
|
glUniform1iARB(tr.liquidShader.u_DepthMap, 2);
|
||
|
glUniform1iARB(tr.liquidShader.u_NormalMap, 3);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.liquidShader.program);
|
||
|
GLSL_ShowProgramUniforms(tr.liquidShader.program);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// volumetric fog post process effect
|
||
|
GLSL_InitGPUShader(&tr.volumetricFogShader, "volumetricFog", ATTR_POSITION, qtrue, qtrue);
|
||
|
|
||
|
tr.volumetricFogShader.u_DepthMap = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_DepthMap");
|
||
|
tr.volumetricFogShader.u_DepthMapBack = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_DepthMapBack");
|
||
|
tr.volumetricFogShader.u_DepthMapFront = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_DepthMapFront");
|
||
|
tr.volumetricFogShader.u_ViewOrigin = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_ViewOrigin");
|
||
|
tr.volumetricFogShader.u_FogDensity = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_FogDensity");
|
||
|
tr.volumetricFogShader.u_FogColor = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_FogColor");
|
||
|
tr.volumetricFogShader.u_UnprojectMatrix = glGetUniformLocationARB(tr.volumetricFogShader.program, "u_UnprojectMatrix");
|
||
|
tr.volumetricFogShader.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.volumetricFogShader.program, "u_ModelViewProjectionMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.volumetricFogShader.program);
|
||
|
glUniform1iARB(tr.volumetricFogShader.u_DepthMap, 0);
|
||
|
glUniform1iARB(tr.volumetricFogShader.u_DepthMapBack, 1);
|
||
|
glUniform1iARB(tr.volumetricFogShader.u_DepthMapFront, 2);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.volumetricFogShader.program);
|
||
|
GLSL_ShowProgramUniforms(tr.volumetricFogShader.program);
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
#ifdef EXPERIMENTAL
|
||
|
// screen space ambien occlusion post process effect
|
||
|
GLSL_InitGPUShader(&tr.screenSpaceAmbientOcclusionShader, "screenSpaceAmbientOcclusion", ATTR_POSITION, qtrue, qtrue);
|
||
|
|
||
|
tr.screenSpaceAmbientOcclusionShader.u_CurrentMap =
|
||
|
glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_CurrentMap");
|
||
|
tr.screenSpaceAmbientOcclusionShader.u_DepthMap =
|
||
|
glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_DepthMap");
|
||
|
tr.screenSpaceAmbientOcclusionShader.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_ModelViewProjectionMatrix");
|
||
|
//tr.screenSpaceAmbientOcclusionShader.u_ViewOrigin = glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_ViewOrigin");
|
||
|
//tr.screenSpaceAmbientOcclusionShader.u_SSAOJitter = glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_SSAOJitter");
|
||
|
//tr.screenSpaceAmbientOcclusionShader.u_SSAORadius = glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_SSAORadius");
|
||
|
//tr.screenSpaceAmbientOcclusionShader.u_UnprojectMatrix = glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_UnprojectMatrix");
|
||
|
//tr.screenSpaceAmbientOcclusionShader.u_ProjectMatrix = glGetUniformLocationARB(tr.screenSpaceAmbientOcclusionShader.program, "u_ProjectMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.screenSpaceAmbientOcclusionShader.program);
|
||
|
glUniform1iARB(tr.screenSpaceAmbientOcclusionShader.u_CurrentMap, 0);
|
||
|
glUniform1iARB(tr.screenSpaceAmbientOcclusionShader.u_DepthMap, 1);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.screenSpaceAmbientOcclusionShader.program);
|
||
|
GLSL_ShowProgramUniforms(tr.screenSpaceAmbientOcclusionShader.program);
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
#ifdef EXPERIMENTAL
|
||
|
// depth of field post process effect
|
||
|
GLSL_InitGPUShader(&tr.depthOfFieldShader, "depthOfField", ATTR_POSITION, qtrue, qtrue);
|
||
|
|
||
|
tr.depthOfFieldShader.u_CurrentMap = glGetUniformLocationARB(tr.depthOfFieldShader.program, "u_CurrentMap");
|
||
|
tr.depthOfFieldShader.u_DepthMap = glGetUniformLocationARB(tr.depthOfFieldShader.program, "u_DepthMap");
|
||
|
tr.depthOfFieldShader.u_ModelViewProjectionMatrix =
|
||
|
glGetUniformLocationARB(tr.depthOfFieldShader.program, "u_ModelViewProjectionMatrix");
|
||
|
|
||
|
glUseProgramObjectARB(tr.depthOfFieldShader.program);
|
||
|
glUniform1iARB(tr.depthOfFieldShader.u_CurrentMap, 0);
|
||
|
glUniform1iARB(tr.depthOfFieldShader.u_DepthMap, 1);
|
||
|
glUseProgramObjectARB(0);
|
||
|
|
||
|
GLSL_ValidateProgram(tr.depthOfFieldShader.program);
|
||
|
GLSL_ShowProgramUniforms(tr.depthOfFieldShader.program);
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
endTime = ri.Milliseconds();
|
||
|
|
||
|
#if defined(USE_GLSL_OPTIMIZER)
|
||
|
glslopt_cleanup(s_glslOptimizer);
|
||
|
#endif
|
||
|
|
||
|
ri.Printf(PRINT_ALL, "GLSL shaders load time = %5.2f seconds\n", (endTime - startTime) / 1000.0);
|
||
|
}
|
||
|
|
||
|
void GLSL_ShutdownGPUShaders(void)
|
||
|
{
|
||
|
// int i;
|
||
|
|
||
|
ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n");
|
||
|
|
||
|
if(gl_genericShader)
|
||
|
{
|
||
|
delete gl_genericShader;
|
||
|
gl_genericShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_vertexLightingShader_DBS_entity)
|
||
|
{
|
||
|
delete gl_vertexLightingShader_DBS_entity;
|
||
|
gl_vertexLightingShader_DBS_entity = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_vertexLightingShader_DBS_world)
|
||
|
{
|
||
|
delete gl_vertexLightingShader_DBS_world;
|
||
|
gl_vertexLightingShader_DBS_world = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_lightMappingShader)
|
||
|
{
|
||
|
delete gl_lightMappingShader;
|
||
|
gl_lightMappingShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_geometricFillShader)
|
||
|
{
|
||
|
delete gl_geometricFillShader;
|
||
|
gl_geometricFillShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_deferredLightingShader_omniXYZ)
|
||
|
{
|
||
|
delete gl_deferredLightingShader_omniXYZ;
|
||
|
gl_deferredLightingShader_omniXYZ = NULL;
|
||
|
}
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
if(tr.depthToColorShader.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.depthToColorShader.program);
|
||
|
Com_Memset(&tr.depthToColorShader, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
if(gl_shadowFillShader)
|
||
|
{
|
||
|
delete gl_shadowFillShader;
|
||
|
gl_shadowFillShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_forwardLightingShader_omniXYZ)
|
||
|
{
|
||
|
delete gl_forwardLightingShader_omniXYZ;
|
||
|
gl_forwardLightingShader_omniXYZ = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_forwardLightingShader_projXYZ)
|
||
|
{
|
||
|
delete gl_forwardLightingShader_projXYZ;
|
||
|
gl_forwardLightingShader_projXYZ = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_forwardLightingShader_directionalSun)
|
||
|
{
|
||
|
delete gl_forwardLightingShader_directionalSun;
|
||
|
gl_forwardLightingShader_directionalSun = NULL;
|
||
|
}
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
#ifdef VOLUMETRIC_LIGHTING
|
||
|
if(tr.lightVolumeShader_omni.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.lightVolumeShader_omni.program);
|
||
|
Com_Memset(&tr.lightVolumeShader_omni, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if(tr.deferredShadowingShader_proj.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.deferredShadowingShader_proj.program);
|
||
|
Com_Memset(&tr.deferredShadowingShader_proj, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
if(gl_reflectionShader)
|
||
|
{
|
||
|
delete gl_reflectionShader;
|
||
|
gl_reflectionShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_skyboxShader)
|
||
|
{
|
||
|
delete gl_skyboxShader;
|
||
|
gl_skyboxShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_fogQuake3Shader)
|
||
|
{
|
||
|
delete gl_fogQuake3Shader;
|
||
|
gl_fogQuake3Shader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_fogGlobalShader)
|
||
|
{
|
||
|
delete gl_fogGlobalShader;
|
||
|
gl_fogGlobalShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_heatHazeShader)
|
||
|
{
|
||
|
delete gl_heatHazeShader;
|
||
|
gl_heatHazeShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_screenShader)
|
||
|
{
|
||
|
delete gl_screenShader;
|
||
|
gl_screenShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_portalShader)
|
||
|
{
|
||
|
delete gl_portalShader;
|
||
|
gl_portalShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_toneMappingShader)
|
||
|
{
|
||
|
delete gl_toneMappingShader;
|
||
|
gl_toneMappingShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_contrastShader)
|
||
|
{
|
||
|
delete gl_contrastShader;
|
||
|
gl_contrastShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_cameraEffectsShader)
|
||
|
{
|
||
|
delete gl_cameraEffectsShader;
|
||
|
gl_cameraEffectsShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_blurXShader)
|
||
|
{
|
||
|
delete gl_blurXShader;
|
||
|
gl_blurXShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_blurYShader)
|
||
|
{
|
||
|
delete gl_blurYShader;
|
||
|
gl_blurYShader = NULL;
|
||
|
}
|
||
|
|
||
|
if(gl_debugShadowMapShader)
|
||
|
{
|
||
|
delete gl_debugShadowMapShader;
|
||
|
gl_debugShadowMapShader = NULL;
|
||
|
}
|
||
|
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
if(tr.liquidShader.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.liquidShader.program);
|
||
|
Com_Memset(&tr.liquidShader, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
|
||
|
if(tr.volumetricFogShader.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.volumetricFogShader.program);
|
||
|
Com_Memset(&tr.volumetricFogShader, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
#ifdef EXPERIMENTAL
|
||
|
if(tr.screenSpaceAmbientOcclusionShader.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.screenSpaceAmbientOcclusionShader.program);
|
||
|
Com_Memset(&tr.screenSpaceAmbientOcclusionShader, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef EXPERIMENTAL
|
||
|
if(tr.depthOfFieldShader.program)
|
||
|
{
|
||
|
glDeleteObjectARB(tr.depthOfFieldShader.program);
|
||
|
Com_Memset(&tr.depthOfFieldShader, 0, sizeof(shaderProgram_t));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#endif // #if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
|
||
|
glState.currentProgram = 0;
|
||
|
if(glUseProgramObjectARB != NULL)
|
||
|
{
|
||
|
glUseProgramObjectARB(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
static void MyMultiDrawElements(GLenum mode, const GLsizei *count, GLenum type, const void* *indices, GLsizei primcount)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < primcount; i++)
|
||
|
{
|
||
|
if (count[i] > 0)
|
||
|
glDrawElements(mode, count[i], type, indices[i]);
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
Tess_DrawElements
|
||
|
==================
|
||
|
*/
|
||
|
void Tess_DrawElements()
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if((tess.numIndexes == 0 || tess.numVertexes == 0) && tess.multiDrawPrimitives == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// move tess data through the GPU, finally
|
||
|
if(glState.currentVBO && glState.currentIBO)
|
||
|
{
|
||
|
if(tess.multiDrawPrimitives)
|
||
|
{
|
||
|
glMultiDrawElements(GL_TRIANGLES, tess.multiDrawCounts, GL_INDEX_TYPE, (const GLvoid**) tess.multiDrawIndexes, tess.multiDrawPrimitives);
|
||
|
|
||
|
backEnd.pc.c_multiDrawElements++;
|
||
|
backEnd.pc.c_multiDrawPrimitives += tess.multiDrawPrimitives;
|
||
|
|
||
|
backEnd.pc.c_vboVertexes += tess.numVertexes;
|
||
|
|
||
|
for(i = 0; i < tess.multiDrawPrimitives; i++)
|
||
|
{
|
||
|
backEnd.pc.c_multiVboIndexes += tess.multiDrawCounts[i];
|
||
|
backEnd.pc.c_indexes += tess.multiDrawCounts[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0));
|
||
|
|
||
|
backEnd.pc.c_drawElements++;
|
||
|
|
||
|
backEnd.pc.c_vboVertexes += tess.numVertexes;
|
||
|
backEnd.pc.c_vboIndexes += tess.numIndexes;
|
||
|
|
||
|
backEnd.pc.c_indexes += tess.numIndexes;
|
||
|
backEnd.pc.c_vertexes += tess.numVertexes;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, tess.indexes);
|
||
|
|
||
|
backEnd.pc.c_drawElements++;
|
||
|
|
||
|
backEnd.pc.c_indexes += tess.numIndexes;
|
||
|
backEnd.pc.c_vertexes += tess.numVertexes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
=============================================================
|
||
|
|
||
|
SURFACE SHADERS
|
||
|
|
||
|
=============================================================
|
||
|
*/
|
||
|
|
||
|
shaderCommands_t tess;
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
BindLightMap
|
||
|
=================
|
||
|
*/
|
||
|
static void BindLightMap()
|
||
|
{
|
||
|
image_t *lightmap;
|
||
|
|
||
|
if(tess.lightmapNum >= 0 && tess.lightmapNum < tr.lightmaps.currentElements)
|
||
|
{
|
||
|
#if defined(COMPAT_Q3A)
|
||
|
lightmap = tr.fatLightmap;
|
||
|
#else
|
||
|
lightmap = (image_t *) Com_GrowListElement(&tr.lightmaps, tess.lightmapNum);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lightmap = NULL;
|
||
|
}
|
||
|
|
||
|
if(!tr.lightmaps.currentElements || !lightmap)
|
||
|
{
|
||
|
GL_Bind(tr.whiteImage);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GL_Bind(lightmap);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
BindDeluxeMap
|
||
|
=================
|
||
|
*/
|
||
|
static void BindDeluxeMap()
|
||
|
{
|
||
|
image_t *deluxemap;
|
||
|
|
||
|
if(tess.lightmapNum >= 0 && tess.lightmapNum < tr.deluxemaps.currentElements)
|
||
|
{
|
||
|
deluxemap = (image_t *) Com_GrowListElement(&tr.deluxemaps, tess.lightmapNum);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
deluxemap = NULL;
|
||
|
}
|
||
|
|
||
|
if(!tr.deluxemaps.currentElements || !deluxemap)
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GL_Bind(deluxemap);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
================
|
||
|
DrawTris
|
||
|
|
||
|
Draws triangle outlines for debugging
|
||
|
================
|
||
|
*/
|
||
|
static void DrawTris()
|
||
|
{
|
||
|
GLimp_LogComment("--- DrawTris ---\n");
|
||
|
|
||
|
gl_genericShader->DisableAlphaTesting();
|
||
|
gl_genericShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_genericShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_genericShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_genericShader->DisableDeformVertexes();
|
||
|
gl_genericShader->DisableTCGenEnvironment();
|
||
|
|
||
|
gl_genericShader->BindProgram();
|
||
|
gl_genericShader->SetRequiredVertexPointers();
|
||
|
|
||
|
GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE);
|
||
|
|
||
|
if(r_showBatches->integer || r_showLightBatches->integer)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_Color(g_color_table[backEnd.pc.c_batches % 8]);
|
||
|
}
|
||
|
else if(glState.currentVBO == tess.vbo)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_Color(colorRed);
|
||
|
}
|
||
|
else if(glState.currentVBO)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_Color(colorBlue);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gl_genericShader->SetUniform_Color(colorWhite);
|
||
|
}
|
||
|
|
||
|
gl_genericShader->SetUniform_ColorModulate(CGEN_CONST, AGEN_CONST);
|
||
|
|
||
|
gl_genericShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_genericShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(tr.whiteImage);
|
||
|
gl_genericShader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
glDepthRange(0, 0);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
glDepthRange(0, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
Tess_Begin
|
||
|
|
||
|
We must set some things up before beginning any tesselation,
|
||
|
because a surface may be forced to perform a Tess_End due
|
||
|
to overflow.
|
||
|
==============
|
||
|
*/
|
||
|
// *INDENT-OFF*
|
||
|
void Tess_Begin( void (*stageIteratorFunc)(),
|
||
|
void (*stageIteratorFunc2)(),
|
||
|
shader_t * surfaceShader, shader_t * lightShader,
|
||
|
qboolean skipTangentSpaces,
|
||
|
qboolean skipVBO,
|
||
|
int lightmapNum,
|
||
|
int fogNum)
|
||
|
{
|
||
|
shader_t *state;
|
||
|
|
||
|
tess.numIndexes = 0;
|
||
|
tess.numVertexes = 0;
|
||
|
|
||
|
tess.multiDrawPrimitives = 0;
|
||
|
|
||
|
// materials are optional
|
||
|
if(surfaceShader != NULL)
|
||
|
{
|
||
|
state = (surfaceShader->remappedShader) ? surfaceShader->remappedShader : surfaceShader;
|
||
|
|
||
|
tess.surfaceShader = state;
|
||
|
tess.surfaceStages = state->stages;
|
||
|
tess.numSurfaceStages = state->numStages;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
state = NULL;
|
||
|
|
||
|
tess.numSurfaceStages = 0;
|
||
|
tess.surfaceShader = NULL;
|
||
|
tess.surfaceStages = NULL;
|
||
|
}
|
||
|
|
||
|
bool isSky = (state != NULL && state->isSky != qfalse);
|
||
|
|
||
|
tess.lightShader = lightShader;
|
||
|
|
||
|
tess.stageIteratorFunc = stageIteratorFunc;
|
||
|
tess.stageIteratorFunc2 = stageIteratorFunc2;
|
||
|
|
||
|
if(!tess.stageIteratorFunc)
|
||
|
{
|
||
|
//tess.stageIteratorFunc = &Tess_StageIteratorGeneric;
|
||
|
ri.Error(ERR_FATAL, "tess.stageIteratorFunc == NULL");
|
||
|
}
|
||
|
|
||
|
if(tess.stageIteratorFunc == &Tess_StageIteratorGeneric)
|
||
|
{
|
||
|
if(isSky)
|
||
|
{
|
||
|
tess.stageIteratorFunc = &Tess_StageIteratorSky;
|
||
|
tess.stageIteratorFunc2 = &Tess_StageIteratorGeneric;
|
||
|
}
|
||
|
}
|
||
|
else if(tess.stageIteratorFunc == &Tess_StageIteratorDepthFill)
|
||
|
{
|
||
|
if(isSky)
|
||
|
{
|
||
|
tess.stageIteratorFunc = &Tess_StageIteratorSky;
|
||
|
tess.stageIteratorFunc2 = &Tess_StageIteratorDepthFill;
|
||
|
}
|
||
|
}
|
||
|
else if(tess.stageIteratorFunc == Tess_StageIteratorGBuffer)
|
||
|
{
|
||
|
if(isSky)
|
||
|
{
|
||
|
tess.stageIteratorFunc = &Tess_StageIteratorSky;
|
||
|
tess.stageIteratorFunc2 = &Tess_StageIteratorGBuffer;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
tess.skipTangentSpaces = skipTangentSpaces;
|
||
|
tess.skipVBO = skipVBO;
|
||
|
tess.lightmapNum = lightmapNum;
|
||
|
tess.fogNum = fogNum;
|
||
|
|
||
|
if(r_logFile->integer)
|
||
|
{
|
||
|
// don't just call LogComment, or we will get
|
||
|
// a call to va() every frame!
|
||
|
GLimp_LogComment(va("--- Tess_Begin( surfaceShader = %s, lightShader = %s, skipTangentSpaces = %i, lightmapNum = %i, fogNum = %i) ---\n", tess.surfaceShader->name, tess.lightShader ? tess.lightShader->name : NULL, tess.skipTangentSpaces, tess.lightmapNum, tess.fogNum));
|
||
|
}
|
||
|
}
|
||
|
// *INDENT-ON*
|
||
|
|
||
|
static void Render_generic(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage;
|
||
|
colorGen_t rgbGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
|
||
|
GLimp_LogComment("--- Render_generic ---\n");
|
||
|
|
||
|
pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_genericShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
gl_genericShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_genericShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_genericShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_genericShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetTCGenEnvironment(pStage->tcGen_Environment);
|
||
|
|
||
|
gl_genericShader->BindProgram();
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// set uniforms
|
||
|
if(pStage->tcGen_Environment)
|
||
|
{
|
||
|
// calculate the environment texcoords in object space
|
||
|
gl_genericShader->SetUniform_ViewOrigin(backEnd.orientation.viewOrigin);
|
||
|
}
|
||
|
|
||
|
// u_AlphaTest
|
||
|
gl_genericShader->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
// u_ColorGen
|
||
|
switch (pStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
rgbGen = pStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
rgbGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// u_AlphaGen
|
||
|
switch (pStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = pStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// u_ColorModulate
|
||
|
gl_genericShader->SetUniform_ColorModulate(rgbGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
gl_genericShader->SetUniform_Color(tess.svars.color);
|
||
|
|
||
|
gl_genericShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_genericShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_genericShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
BindAnimatedImage(&pStage->bundle[TB_COLORMAP]);
|
||
|
gl_genericShader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
gl_genericShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_vertexLighting_DBS_entity(int stage)
|
||
|
{
|
||
|
vec3_t viewOrigin;
|
||
|
vec3_t ambientColor;
|
||
|
vec3_t lightDir;
|
||
|
vec4_t lightColor;
|
||
|
uint32_t stateBits;
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_vertexLighting_DBS_entity ---\n");
|
||
|
|
||
|
stateBits = pStage->stateBits;
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (pStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_vertexLightingShader_DBS_entity->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_vertexLightingShader_DBS_entity->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_vertexLightingShader_DBS_entity->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetNormalMapping(normalMapping);
|
||
|
gl_vertexLightingShader_DBS_entity->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetReflectiveSpecular(normalMapping && tr.cubeHashTable != NULL);
|
||
|
|
||
|
// gl_vertexLightingShader_DBS_entity->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin); // in world space
|
||
|
VectorCopy(backEnd.currentEntity->ambientLight, ambientColor);
|
||
|
//ClampColor(ambientColor);
|
||
|
VectorCopy(backEnd.currentEntity->directedLight, lightColor);
|
||
|
//ClampColor(directedLight);
|
||
|
|
||
|
// lightDir = L vector which means surface to light
|
||
|
VectorCopy(backEnd.currentEntity->lightDir, lightDir);
|
||
|
|
||
|
// u_AlphaTest
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_AmbientColor(ambientColor);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_ViewOrigin(viewOrigin);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_LightDir(lightDir);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_LightColor(lightColor);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(r_parallaxMapping->integer && tess.surfaceShader->parallax)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&pStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(pStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(pStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
|
||
|
|
||
|
//if(r_reflectionMapping->integer)
|
||
|
{
|
||
|
cubemapProbe_t *cubeProbeNearest;
|
||
|
cubemapProbe_t *cubeProbeSecondNearest;
|
||
|
|
||
|
if(backEnd.currentEntity && (backEnd.currentEntity != &tr.worldEntity))
|
||
|
{
|
||
|
R_FindTwoNearestCubeMaps(backEnd.currentEntity->e.origin, &cubeProbeNearest, &cubeProbeSecondNearest);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// FIXME position
|
||
|
R_FindTwoNearestCubeMaps(backEnd.viewParms.orientation.origin, &cubeProbeNearest, &cubeProbeSecondNearest);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(cubeProbeNearest == NULL && cubeProbeSecondNearest == NULL)
|
||
|
{
|
||
|
GLimp_LogComment("cubeProbeNearest && cubeProbeSecondNearest == NULL\n");
|
||
|
|
||
|
// bind u_EnvironmentMap0
|
||
|
GL_SelectTexture(3);
|
||
|
GL_Bind(tr.whiteCubeImage);
|
||
|
|
||
|
// bind u_EnvironmentMap1
|
||
|
GL_SelectTexture(4);
|
||
|
GL_Bind(tr.whiteCubeImage);
|
||
|
}
|
||
|
else if(cubeProbeNearest == NULL)
|
||
|
{
|
||
|
GLimp_LogComment("cubeProbeNearest == NULL\n");
|
||
|
|
||
|
// bind u_EnvironmentMap0
|
||
|
GL_SelectTexture(3);
|
||
|
GL_Bind(cubeProbeSecondNearest->cubemap);
|
||
|
|
||
|
// u_EnvironmentInterpolation
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_EnvironmentInterpolation(0.0);
|
||
|
}
|
||
|
else if(cubeProbeSecondNearest == NULL)
|
||
|
{
|
||
|
GLimp_LogComment("cubeProbeSecondNearest == NULL\n");
|
||
|
|
||
|
// bind u_EnvironmentMap0
|
||
|
GL_SelectTexture(3);
|
||
|
GL_Bind(cubeProbeNearest->cubemap);
|
||
|
|
||
|
// bind u_EnvironmentMap1
|
||
|
//GL_SelectTexture(4);
|
||
|
//GL_Bind(cubeProbeNearest->cubemap);
|
||
|
|
||
|
// u_EnvironmentInterpolation
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_EnvironmentInterpolation(0.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float cubeProbeNearestDistance, cubeProbeSecondNearestDistance;
|
||
|
|
||
|
if(backEnd.currentEntity && (backEnd.currentEntity != &tr.worldEntity))
|
||
|
{
|
||
|
cubeProbeNearestDistance = Distance(backEnd.currentEntity->e.origin, cubeProbeNearest->origin);
|
||
|
cubeProbeSecondNearestDistance = Distance(backEnd.currentEntity->e.origin, cubeProbeSecondNearest->origin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// FIXME position
|
||
|
cubeProbeNearestDistance = Distance(backEnd.viewParms.orientation.origin, cubeProbeNearest->origin);
|
||
|
cubeProbeSecondNearestDistance = Distance(backEnd.viewParms.orientation.origin, cubeProbeSecondNearest->origin);
|
||
|
}
|
||
|
|
||
|
float interpolate = cubeProbeNearestDistance / (cubeProbeNearestDistance + cubeProbeSecondNearestDistance);
|
||
|
|
||
|
if(r_logFile->integer)
|
||
|
{
|
||
|
GLimp_LogComment(va("cubeProbeNearestDistance = %f, cubeProbeSecondNearestDistance = %f, interpolation = %f\n",
|
||
|
cubeProbeNearestDistance, cubeProbeSecondNearestDistance, interpolate));
|
||
|
}
|
||
|
|
||
|
// bind u_EnvironmentMap0
|
||
|
GL_SelectTexture(3);
|
||
|
GL_Bind(cubeProbeNearest->cubemap);
|
||
|
|
||
|
// bind u_EnvironmentMap1
|
||
|
GL_SelectTexture(4);
|
||
|
GL_Bind(cubeProbeSecondNearest->cubemap);
|
||
|
|
||
|
// u_EnvironmentInterpolation
|
||
|
gl_vertexLightingShader_DBS_entity->SetUniform_EnvironmentInterpolation(interpolate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gl_vertexLightingShader_DBS_entity->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_vertexLighting_DBS_world(int stage)
|
||
|
{
|
||
|
vec3_t viewOrigin;
|
||
|
uint32_t stateBits;
|
||
|
colorGen_t colorGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_vertexLighting_DBS_world ---\n");
|
||
|
|
||
|
stateBits = pStage->stateBits;
|
||
|
|
||
|
bool normalMapping = tr.worldDeluxeMapping && r_normalMapping->integer && (pStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_vertexLightingShader_DBS_world->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_vertexLightingShader_DBS_world->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetNormalMapping(normalMapping);
|
||
|
gl_vertexLightingShader_DBS_world->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
// gl_vertexLightingShader_DBS_world->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.orientation.viewOrigin, viewOrigin);
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
// u_ColorModulate
|
||
|
switch (pStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
colorGen = pStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
colorGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (pStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
alphaGen = pStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = pStage->alphaGen;
|
||
|
|
||
|
/*
|
||
|
alphaGen = AGEN_VERTEX;
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
|
||
|
stateBits |= (GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA);
|
||
|
*/
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_ColorModulate(colorGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
//if(r_showTerrainBlends->integer)
|
||
|
//{
|
||
|
// gl_vertexLightingShader_DBS_world->SetUniform_Color(g_color_table[backEnd.pc.c_batches % 8]);
|
||
|
//}
|
||
|
//else
|
||
|
{
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_Color(tess.svars.color);
|
||
|
}
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_LightWrapAround(RB_EvalExpression(&pStage->wrapAroundLightingExp, 0));
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_ViewOrigin(viewOrigin);
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
if(r_parallaxMapping->integer)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&pStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(pStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(pStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_vertexLightingShader_DBS_world->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
}
|
||
|
|
||
|
gl_vertexLightingShader_DBS_world->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_lightMapping(int stage, bool asColorMap, bool normalMapping)
|
||
|
{
|
||
|
shaderStage_t *pStage;
|
||
|
uint32_t stateBits;
|
||
|
colorGen_t rgbGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
|
||
|
GLimp_LogComment("--- Render_lightMapping ---\n");
|
||
|
|
||
|
pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
stateBits = pStage->stateBits;
|
||
|
|
||
|
switch (pStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
rgbGen = pStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
rgbGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (pStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = pStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(r_showLightMaps->integer)
|
||
|
{
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_ATEST_BITS);
|
||
|
}
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
if(pStage->bundle[TB_NORMALMAP].image[0] == NULL)
|
||
|
{
|
||
|
normalMapping = false;
|
||
|
}
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
|
||
|
gl_lightMappingShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_lightMappingShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_lightMappingShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_lightMappingShader->SetNormalMapping(normalMapping);
|
||
|
gl_lightMappingShader->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
// gl_lightMappingShader->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_lightMappingShader->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_lightMappingShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_lightMappingShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
gl_lightMappingShader->SetUniform_ViewOrigin(backEnd.viewParms.orientation.origin); // in world space
|
||
|
|
||
|
gl_lightMappingShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_lightMappingShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
gl_lightMappingShader->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
// u_ColorModulate
|
||
|
gl_lightMappingShader->SetUniform_ColorModulate(rgbGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
gl_lightMappingShader->SetUniform_Color(tess.svars.color);
|
||
|
|
||
|
if(r_parallaxMapping->integer)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&pStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_lightMappingShader->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_lightMappingShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
if(asColorMap)
|
||
|
{
|
||
|
GL_Bind(tr.whiteImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_lightMappingShader->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
}
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(pStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_lightMappingShader->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(pStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_lightMappingShader->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
|
||
|
// bind u_DeluxeMap
|
||
|
GL_SelectTexture(4);
|
||
|
BindDeluxeMap();
|
||
|
}
|
||
|
|
||
|
// bind u_LightMap
|
||
|
GL_SelectTexture(3);
|
||
|
BindLightMap();
|
||
|
|
||
|
gl_lightMappingShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_geometricFill(int stage, bool cmap2black)
|
||
|
{
|
||
|
shaderStage_t *pStage;
|
||
|
uint32_t stateBits;
|
||
|
vec4_t ambientColor;
|
||
|
|
||
|
GLimp_LogComment("--- Render_geometricFill ---\n");
|
||
|
|
||
|
pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
// remove blend mode
|
||
|
stateBits = pStage->stateBits;
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (pStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_geometricFillShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_geometricFillShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_geometricFillShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_geometricFillShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_geometricFillShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_geometricFillShader->SetNormalMapping(normalMapping);
|
||
|
gl_geometricFillShader->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
gl_geometricFillShader->SetReflectiveSpecular(false);//normalMapping && tr.cubeHashTable != NULL);
|
||
|
|
||
|
// gl_geometricFillShader->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_geometricFillShader->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
/*
|
||
|
{
|
||
|
if(r_precomputedLighting->integer)
|
||
|
{
|
||
|
VectorCopy(backEnd.currentEntity->ambientLight, ambientColor);
|
||
|
ClampColor(ambientColor);
|
||
|
}
|
||
|
else if(r_forceAmbient->integer)
|
||
|
{
|
||
|
ambientColor[0] = r_forceAmbient->value;
|
||
|
ambientColor[1] = r_forceAmbient->value;
|
||
|
ambientColor[2] = r_forceAmbient->value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VectorClear(ambientColor);
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
gl_geometricFillShader->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
gl_geometricFillShader->SetUniform_ViewOrigin(backEnd.viewParms.orientation.origin); // world space
|
||
|
// gl_geometricFillShader->SetUniform_AmbientColor(ambientColor);
|
||
|
|
||
|
gl_geometricFillShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
// gl_geometricFillShader->SetUniform_ModelViewMatrix(glState.modelViewMatrix[glState.stackIndex]);
|
||
|
gl_geometricFillShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_geometricFillShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_geometricFillShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformParms
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_geometricFillShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_geometricFillShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
// u_DepthScale
|
||
|
if(r_parallaxMapping->integer && tess.surfaceShader->parallax)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&pStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_geometricFillShader->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
// u_PortalPlane
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_geometricFillShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
//if(r_deferredShading->integer == DS_STANDARD)
|
||
|
{
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
if(cmap2black)
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
}
|
||
|
gl_geometricFillShader->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
}
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(pStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_geometricFillShader->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
if(r_deferredShading->integer == DS_STANDARD)
|
||
|
{
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(r_forceSpecular->integer)
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
}
|
||
|
else if(pStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_geometricFillShader->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gl_geometricFillShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
|
||
|
static void Render_depthFill(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage;
|
||
|
colorGen_t rgbGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
vec4_t ambientColor;
|
||
|
|
||
|
GLimp_LogComment("--- Render_depthFill ---\n");
|
||
|
|
||
|
pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
uint32_t stateBits = pStage->stateBits;
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_ATEST_BITS);
|
||
|
stateBits |= GLS_DEPTHMASK_TRUE;
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
gl_genericShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
gl_genericShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_genericShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_genericShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_genericShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetTCGenEnvironment(pStage->tcGen_Environment);
|
||
|
|
||
|
gl_genericShader->BindProgram();
|
||
|
|
||
|
// set uniforms
|
||
|
if(pStage->tcGen_Environment)
|
||
|
{
|
||
|
// calculate the environment texcoords in object space
|
||
|
gl_genericShader->SetUniform_ViewOrigin(backEnd.orientation.viewOrigin);
|
||
|
}
|
||
|
|
||
|
// u_AlphaTest
|
||
|
gl_genericShader->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
// u_ColorModulate
|
||
|
gl_genericShader->SetUniform_ColorModulate(CGEN_CONST, AGEN_CONST);
|
||
|
|
||
|
// u_Color
|
||
|
#if 1
|
||
|
if(r_precomputedLighting->integer)
|
||
|
{
|
||
|
VectorCopy(backEnd.currentEntity->ambientLight, ambientColor);
|
||
|
ClampColor(ambientColor);
|
||
|
}
|
||
|
else if(r_forceAmbient->integer)
|
||
|
{
|
||
|
ambientColor[0] = r_forceAmbient->value;
|
||
|
ambientColor[1] = r_forceAmbient->value;
|
||
|
ambientColor[2] = r_forceAmbient->value;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
VectorClear(ambientColor);
|
||
|
}
|
||
|
ambientColor[3] = 1;
|
||
|
gl_genericShader->SetUniform_Color(ambientColor);
|
||
|
#else
|
||
|
gl_genericShader->SetUniform_Color(colorMdGrey);
|
||
|
#endif
|
||
|
|
||
|
gl_genericShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_genericShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_genericShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
if(tess.surfaceShader->alphaTest)
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_genericShader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//GL_Bind(tr.defaultImage);
|
||
|
GL_Bind(pStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_genericShader->SetUniform_ColorTextureMatrix(matrixIdentity);
|
||
|
}
|
||
|
|
||
|
gl_genericShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_shadowFill(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage;
|
||
|
uint32_t stateBits;
|
||
|
|
||
|
|
||
|
GLimp_LogComment("--- Render_shadowFill ---\n");
|
||
|
|
||
|
pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
// remove blend modes
|
||
|
stateBits = pStage->stateBits;
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
|
||
|
gl_shadowFillShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
gl_shadowFillShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_shadowFillShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_shadowFillShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_shadowFillShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
gl_shadowFillShader->SetMacro_LIGHT_DIRECTIONAL(backEnd.currentLight->l.rlType == RL_DIRECTIONAL);
|
||
|
|
||
|
gl_shadowFillShader->BindProgram();
|
||
|
|
||
|
gl_shadowFillShader->SetRequiredVertexPointers();
|
||
|
|
||
|
|
||
|
|
||
|
if(r_debugShadowMaps->integer)
|
||
|
{
|
||
|
vec4_t shadowMapColor;
|
||
|
|
||
|
Vector4Copy(g_color_table[backEnd.pc.c_batches % 8], shadowMapColor);
|
||
|
|
||
|
gl_shadowFillShader->SetUniform_Color(shadowMapColor);
|
||
|
}
|
||
|
|
||
|
gl_shadowFillShader->SetUniform_AlphaTest(pStage->stateBits);
|
||
|
|
||
|
if(backEnd.currentLight->l.rlType != RL_DIRECTIONAL)
|
||
|
{
|
||
|
gl_shadowFillShader->SetUniform_LightOrigin(backEnd.currentLight->origin);
|
||
|
gl_shadowFillShader->SetUniform_LightRadius(backEnd.currentLight->sphereRadius);
|
||
|
}
|
||
|
|
||
|
gl_shadowFillShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_shadowFillShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_shadowFillShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_shadowFillShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_shadowFillShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_shadowFillShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_shadowFillShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
|
||
|
if((pStage->stateBits & GLS_ATEST_BITS) != 0)
|
||
|
{
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
gl_shadowFillShader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.whiteImage);
|
||
|
}
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_forwardLighting_DBS_omni(shaderStage_t * diffuseStage,
|
||
|
shaderStage_t * attenuationXYStage,
|
||
|
shaderStage_t * attenuationZStage, trRefLight_t * light)
|
||
|
{
|
||
|
vec3_t viewOrigin;
|
||
|
vec3_t lightOrigin;
|
||
|
vec4_t lightColor;
|
||
|
float shadowTexelSize;
|
||
|
colorGen_t colorGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
|
||
|
GLimp_LogComment("--- Render_forwardLighting_DBS_omni ---\n");
|
||
|
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (diffuseStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
bool shadowCompare = (r_shadows->integer >= SHADOWING_ESM16 && !light->l.noShadows && light->shadowLOD >= 0);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_forwardLightingShader_omniXYZ->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_forwardLightingShader_omniXYZ->SetAlphaTesting((diffuseStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_forwardLightingShader_omniXYZ->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetNormalMapping(normalMapping);
|
||
|
gl_forwardLightingShader_omniXYZ->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
// gl_forwardLightingShader_omniXYZ->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetShadowing(shadowCompare);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
// u_ColorModulate
|
||
|
switch (diffuseStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
colorGen = diffuseStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
colorGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (diffuseStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = diffuseStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ColorModulate(colorGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_Color(tess.svars.color);
|
||
|
|
||
|
if(r_parallaxMapping->integer)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&diffuseStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin);
|
||
|
VectorCopy(light->origin, lightOrigin);
|
||
|
VectorCopy(tess.svars.color, lightColor);
|
||
|
|
||
|
if(shadowCompare)
|
||
|
shadowTexelSize = 1.0f / shadowMapResolutions[light->shadowLOD];
|
||
|
else
|
||
|
shadowTexelSize = 1.0f;
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ViewOrigin(viewOrigin);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightOrigin(lightOrigin);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightColor(lightColor);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightRadius(light->sphereRadius);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightScale(light->l.scale);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightWrapAround(RB_EvalExpression(&diffuseStage->wrapAroundLightingExp, 0));
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_LightAttenuationMatrix(light->attenuationMatrix2);
|
||
|
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ShadowTexelSize(shadowTexelSize);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ShadowBlur(r_shadowBlur->value);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(diffuseStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(r_forceSpecular->integer)
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
}
|
||
|
else if(diffuseStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_omniXYZ->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
}
|
||
|
|
||
|
// bind u_AttenuationMapXY
|
||
|
GL_SelectTexture(3);
|
||
|
BindAnimatedImage(&attenuationXYStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
// bind u_AttenuationMapZ
|
||
|
GL_SelectTexture(4);
|
||
|
BindAnimatedImage(&attenuationZStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
// bind u_ShadowMap
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
GL_SelectTexture(5);
|
||
|
GL_Bind(tr.shadowCubeFBOImage[light->shadowLOD]);
|
||
|
}
|
||
|
|
||
|
// bind u_RandomMap
|
||
|
GL_SelectTexture(6);
|
||
|
GL_Bind(tr.randomNormalsImage);
|
||
|
|
||
|
gl_forwardLightingShader_omniXYZ->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_forwardLighting_DBS_proj(shaderStage_t * diffuseStage,
|
||
|
shaderStage_t * attenuationXYStage,
|
||
|
shaderStage_t * attenuationZStage, trRefLight_t * light)
|
||
|
{
|
||
|
vec3_t viewOrigin;
|
||
|
vec3_t lightOrigin;
|
||
|
vec4_t lightColor;
|
||
|
float shadowTexelSize;
|
||
|
colorGen_t colorGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
|
||
|
GLimp_LogComment("--- Render_fowardLighting_DBS_proj ---\n");
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (diffuseStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
bool shadowCompare = (r_shadows->integer >= SHADOWING_ESM16 && !light->l.noShadows && light->shadowLOD >= 0);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_forwardLightingShader_projXYZ->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_forwardLightingShader_projXYZ->SetAlphaTesting((diffuseStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_forwardLightingShader_projXYZ->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetNormalMapping(normalMapping);
|
||
|
gl_forwardLightingShader_projXYZ->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
// gl_forwardLightingShader_projXYZ->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetShadowing(shadowCompare);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
// u_ColorModulate
|
||
|
switch (diffuseStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
colorGen = diffuseStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
colorGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (diffuseStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = diffuseStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ColorModulate(colorGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_Color(tess.svars.color);
|
||
|
|
||
|
if(r_parallaxMapping->integer)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&diffuseStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin);
|
||
|
VectorCopy(light->origin, lightOrigin);
|
||
|
VectorCopy(tess.svars.color, lightColor);
|
||
|
|
||
|
if(shadowCompare)
|
||
|
shadowTexelSize = 1.0f / shadowMapResolutions[light->shadowLOD];
|
||
|
else
|
||
|
shadowTexelSize = 1.0f;
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ViewOrigin(viewOrigin);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightOrigin(lightOrigin);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightColor(lightColor);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightRadius(light->sphereRadius);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightScale(light->l.scale);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightWrapAround(RB_EvalExpression(&diffuseStage->wrapAroundLightingExp, 0));
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_LightAttenuationMatrix(light->attenuationMatrix2);
|
||
|
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ShadowTexelSize(shadowTexelSize);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ShadowBlur(r_shadowBlur->value);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ShadowMatrix(light->shadowMatrices);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(diffuseStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(r_forceSpecular->integer)
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
}
|
||
|
else if(diffuseStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_projXYZ->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
}
|
||
|
|
||
|
// bind u_AttenuationMapXY
|
||
|
GL_SelectTexture(3);
|
||
|
BindAnimatedImage(&attenuationXYStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
// bind u_AttenuationMapZ
|
||
|
GL_SelectTexture(4);
|
||
|
BindAnimatedImage(&attenuationZStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
// bind u_ShadowMap
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
GL_SelectTexture(5);
|
||
|
GL_Bind(tr.shadowMapFBOImage[light->shadowLOD]);
|
||
|
}
|
||
|
|
||
|
// bind u_RandomMap
|
||
|
GL_SelectTexture(6);
|
||
|
GL_Bind(tr.randomNormalsImage);
|
||
|
|
||
|
gl_forwardLightingShader_projXYZ->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_forwardLighting_DBS_directional(shaderStage_t * diffuseStage,
|
||
|
shaderStage_t * attenuationXYStage,
|
||
|
shaderStage_t * attenuationZStage, trRefLight_t * light)
|
||
|
{
|
||
|
#if 1
|
||
|
vec3_t viewOrigin;
|
||
|
vec3_t lightDirection;
|
||
|
vec4_t lightColor;
|
||
|
float shadowTexelSize;
|
||
|
colorGen_t colorGen;
|
||
|
alphaGen_t alphaGen;
|
||
|
|
||
|
GLimp_LogComment("--- Render_forwardLighting_DBS_directional ---\n");
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (diffuseStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
bool shadowCompare = (r_shadows->integer >= SHADOWING_ESM16 && !light->l.noShadows && light->shadowLOD >= 0);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_forwardLightingShader_directionalSun->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_forwardLightingShader_directionalSun->SetAlphaTesting((diffuseStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_forwardLightingShader_directionalSun->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetNormalMapping(normalMapping);
|
||
|
gl_forwardLightingShader_directionalSun->SetParallaxMapping(normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax);
|
||
|
|
||
|
// gl_forwardLightingShader_directionalSun->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetShadowing(shadowCompare);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// now we are ready to set the shader program uniforms
|
||
|
|
||
|
// u_ColorModulate
|
||
|
switch (diffuseStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
colorGen = diffuseStage->rgbGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
colorGen = CGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (diffuseStage->alphaGen)
|
||
|
{
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
alphaGen = diffuseStage->alphaGen;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alphaGen = AGEN_CONST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ColorModulate(colorGen, alphaGen);
|
||
|
|
||
|
// u_Color
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_Color(tess.svars.color);
|
||
|
|
||
|
if(r_parallaxMapping->integer)
|
||
|
{
|
||
|
float depthScale;
|
||
|
|
||
|
depthScale = RB_EvalExpression(&diffuseStage->depthScaleExp, r_parallaxDepthScale->value);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_DepthScale(depthScale);
|
||
|
}
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin);
|
||
|
|
||
|
#if 1
|
||
|
VectorCopy(tr.sunDirection, lightDirection);
|
||
|
#else
|
||
|
VectorCopy(light->direction, lightDirection);
|
||
|
#endif
|
||
|
|
||
|
VectorCopy(tess.svars.color, lightColor);
|
||
|
|
||
|
if(shadowCompare)
|
||
|
shadowTexelSize = 1.0f / sunShadowMapResolutions[light->shadowLOD];
|
||
|
else
|
||
|
shadowTexelSize = 1.0f;
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ViewOrigin(viewOrigin);
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightDir(lightDirection);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightColor(lightColor);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightRadius(light->sphereRadius);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightScale(light->l.scale);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightWrapAround(RB_EvalExpression(&diffuseStage->wrapAroundLightingExp, 0));
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_LightAttenuationMatrix(light->attenuationMatrix2);
|
||
|
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ShadowMatrix(light->shadowMatricesBiased);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ShadowParallelSplitDistances(backEnd.viewParms.parallelSplitDistances);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ShadowTexelSize(shadowTexelSize);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ShadowBlur(r_shadowBlur->value);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ViewMatrix(backEnd.viewParms.world.viewMatrix);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// bind u_DiffuseMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_DiffuseTextureMatrix(tess.svars.texMatrices[TB_DIFFUSEMAP]);
|
||
|
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(diffuseStage->bundle[TB_NORMALMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.flatImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
|
||
|
// bind u_SpecularMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(r_forceSpecular->integer)
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_DIFFUSEMAP].image[0]);
|
||
|
}
|
||
|
else if(diffuseStage->bundle[TB_SPECULARMAP].image[0])
|
||
|
{
|
||
|
GL_Bind(diffuseStage->bundle[TB_SPECULARMAP].image[0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.blackImage);
|
||
|
}
|
||
|
gl_forwardLightingShader_directionalSun->SetUniform_SpecularTextureMatrix(tess.svars.texMatrices[TB_SPECULARMAP]);
|
||
|
}
|
||
|
|
||
|
// bind u_ShadowMap
|
||
|
if(shadowCompare)
|
||
|
{
|
||
|
GL_SelectTexture(5);
|
||
|
GL_Bind(tr.sunShadowMapFBOImage[0]);
|
||
|
|
||
|
if(r_parallelShadowSplits->integer >= 1)
|
||
|
{
|
||
|
GL_SelectTexture(6);
|
||
|
GL_Bind(tr.sunShadowMapFBOImage[1]);
|
||
|
}
|
||
|
|
||
|
if(r_parallelShadowSplits->integer >= 2)
|
||
|
{
|
||
|
GL_SelectTexture(7);
|
||
|
GL_Bind(tr.sunShadowMapFBOImage[2]);
|
||
|
}
|
||
|
|
||
|
if(r_parallelShadowSplits->integer >= 3)
|
||
|
{
|
||
|
GL_SelectTexture(8);
|
||
|
GL_Bind(tr.sunShadowMapFBOImage[3]);
|
||
|
}
|
||
|
|
||
|
if(r_parallelShadowSplits->integer >= 4)
|
||
|
{
|
||
|
GL_SelectTexture(9);
|
||
|
GL_Bind(tr.sunShadowMapFBOImage[4]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
gl_forwardLightingShader_directionalSun->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void Render_reflection_CB(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_reflection_CB ---\n");
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
bool normalMapping = r_normalMapping->integer && (pStage->bundle[TB_NORMALMAP].image[0] != NULL);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_reflectionShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
// gl_reflectionShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_reflectionShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_reflectionShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_reflectionShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_reflectionShader->SetNormalMapping(normalMapping);
|
||
|
|
||
|
// gl_reflectionShader->SetMacro_TWOSIDED(tess.surfaceShader->cullType);
|
||
|
|
||
|
gl_reflectionShader->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
|
||
|
gl_reflectionShader->SetUniform_ViewOrigin(backEnd.viewParms.orientation.origin); // in world space
|
||
|
|
||
|
gl_reflectionShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_reflectionShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_reflectionShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_reflectionShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
#if 1
|
||
|
if(backEnd.currentEntity && (backEnd.currentEntity != &tr.worldEntity))
|
||
|
{
|
||
|
GL_BindNearestCubeMap(backEnd.currentEntity->e.origin);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_BindNearestCubeMap(backEnd.viewParms.orientation.origin);
|
||
|
}
|
||
|
#else
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
#endif
|
||
|
|
||
|
// bind u_NormalMap
|
||
|
if(normalMapping)
|
||
|
{
|
||
|
GL_SelectTexture(1);
|
||
|
GL_Bind(pStage->bundle[TB_NORMALMAP].image[0]);
|
||
|
gl_reflectionShader->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_NORMALMAP]);
|
||
|
}
|
||
|
|
||
|
gl_reflectionShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_dispersion_C(int stage)
|
||
|
{
|
||
|
#if 0 //!defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
vec3_t viewOrigin;
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
float eta;
|
||
|
float etaDelta;
|
||
|
|
||
|
GLimp_LogComment("--- Render_dispersion_C ---\n");
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
// enable shader, set arrays
|
||
|
GL_BindProgram(&tr.dispersionShader_C);
|
||
|
GL_VertexAttribsState(tr.dispersionShader_C.attribs);
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin); // in world space
|
||
|
eta = RB_EvalExpression(&pStage->etaExp, (float)1.1);
|
||
|
etaDelta = RB_EvalExpression(&pStage->etaDeltaExp, (float)-0.02);
|
||
|
|
||
|
GLSL_SetUniform_ViewOrigin(&tr.dispersionShader_C, viewOrigin);
|
||
|
glUniform3fARB(tr.dispersionShader_C.u_EtaRatio, eta, eta + etaDelta, eta + (etaDelta * 2));
|
||
|
glUniform1fARB(tr.dispersionShader_C.u_FresnelPower, RB_EvalExpression(&pStage->fresnelPowerExp, 2.0f));
|
||
|
glUniform1fARB(tr.dispersionShader_C.u_FresnelScale, RB_EvalExpression(&pStage->fresnelScaleExp, 2.0f));
|
||
|
glUniform1fARB(tr.dispersionShader_C.u_FresnelBias, RB_EvalExpression(&pStage->fresnelBiasExp, 1.0f));
|
||
|
|
||
|
GLSL_SetUniform_ModelMatrix(&tr.dispersionShader_C, backEnd.orientation.transformMatrix);
|
||
|
GLSL_SetUniform_ModelViewProjectionMatrix(&tr.dispersionShader_C, glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
if(glConfig2.vboVertexSkinningAvailable)
|
||
|
{
|
||
|
GLSL_SetUniform_VertexSkinning(&tr.dispersionShader_C, tess.vboVertexSkinning);
|
||
|
|
||
|
if(tess.vboVertexSkinning)
|
||
|
glUniformMatrix4fvARB(tr.dispersionShader_C.u_BoneMatrix, MAX_BONES, GL_FALSE, &tess.boneMatrices[0][0]);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void Render_skybox(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_skybox ---\n");
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
gl_skyboxShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
gl_skyboxShader->BindProgram();
|
||
|
|
||
|
gl_skyboxShader->SetUniform_ViewOrigin(backEnd.viewParms.orientation.origin); // in world space
|
||
|
|
||
|
gl_skyboxShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_skyboxShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_PortalPlane
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_skyboxShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
|
||
|
gl_skyboxShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_screen(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_screen ---\n");
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
gl_screenShader->BindProgram();
|
||
|
|
||
|
/*
|
||
|
if(pStage->vertexColor || pStage->inverseVertexColor)
|
||
|
{
|
||
|
GL_VertexAttribsState(tr.screenShader.attribs);
|
||
|
}
|
||
|
else
|
||
|
*/
|
||
|
{
|
||
|
GL_VertexAttribsState(ATTR_POSITION);
|
||
|
glVertexAttrib4fvARB(ATTR_INDEX_COLOR, tess.svars.color);
|
||
|
}
|
||
|
|
||
|
gl_screenShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// bind u_CurrentMap
|
||
|
GL_SelectTexture(0);
|
||
|
BindAnimatedImage(&pStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_portal(int stage)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_portal ---\n");
|
||
|
|
||
|
GL_State(pStage->stateBits);
|
||
|
|
||
|
// enable shader, set arrays
|
||
|
gl_portalShader->BindProgram();
|
||
|
|
||
|
/*
|
||
|
if(pStage->vertexColor || pStage->inverseVertexColor)
|
||
|
{
|
||
|
GL_VertexAttribsState(tr.portalShader.attribs);
|
||
|
}
|
||
|
else
|
||
|
*/
|
||
|
{
|
||
|
GL_VertexAttribsState(ATTR_POSITION);
|
||
|
glVertexAttrib4fvARB(ATTR_INDEX_COLOR, tess.svars.color);
|
||
|
}
|
||
|
|
||
|
gl_portalShader->SetUniform_PortalRange(tess.surfaceShader->portalRange);
|
||
|
|
||
|
gl_portalShader->SetUniform_ModelViewMatrix(glState.modelViewMatrix[glState.stackIndex]);
|
||
|
gl_portalShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// bind u_CurrentMap
|
||
|
GL_SelectTexture(0);
|
||
|
BindAnimatedImage(&pStage->bundle[TB_COLORMAP]);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_heatHaze(int stage)
|
||
|
{
|
||
|
uint32_t stateBits;
|
||
|
float deformMagnitude;
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_heatHaze ---\n");
|
||
|
|
||
|
if(r_heatHazeFix->integer && glConfig2.framebufferBlitAvailable /*&& glConfig.hardwareType != GLHW_ATI && glConfig.hardwareType != GLHW_ATI_DX10*/ && glConfig.driverType != GLDRV_MESA)
|
||
|
{
|
||
|
FBO_t *previousFBO;
|
||
|
uint32_t stateBits;
|
||
|
|
||
|
GLimp_LogComment("--- HEATHAZE FIX BEGIN ---\n");
|
||
|
|
||
|
// capture current color buffer for u_CurrentMap
|
||
|
/*
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(tr.currentRenderImage);
|
||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderImage->uploadWidth,
|
||
|
tr.currentRenderImage->uploadHeight);
|
||
|
|
||
|
*/
|
||
|
|
||
|
previousFBO = glState.currentFBO;
|
||
|
|
||
|
if(DS_STANDARD_ENABLED())
|
||
|
{
|
||
|
// copy deferredRenderFBO to occlusionRenderFBO
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.geometricRenderFBO->frameBuffer);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, tr.deferredRenderFBO->width, tr.deferredRenderFBO->height,
|
||
|
0, 0, tr.occlusionRenderFBO->width, tr.occlusionRenderFBO->height,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
}
|
||
|
else if(HDR_ENABLED())
|
||
|
{
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// copy deferredRenderFBO to occlusionRenderFBO
|
||
|
#if 0
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, tr.deferredRenderFBO->width, tr.deferredRenderFBO->height,
|
||
|
0, 0, tr.occlusionRenderFBO->width, tr.occlusionRenderFBO->height,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
#else
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
#endif
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// copy depth of the main context to occlusionRenderFBO
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
}
|
||
|
|
||
|
R_BindFBO(tr.occlusionRenderFBO);
|
||
|
R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.occlusionRenderFBOImage->texnum, 0);
|
||
|
|
||
|
// clear color buffer
|
||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||
|
|
||
|
// remove blend mode
|
||
|
stateBits = pStage->stateBits;
|
||
|
stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE);
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
//gl_genericShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
gl_genericShader->SetAlphaTesting(false);
|
||
|
gl_genericShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_genericShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_genericShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_genericShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetTCGenEnvironment(false);
|
||
|
|
||
|
gl_genericShader->BindProgram();
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// u_ColorModulate
|
||
|
gl_genericShader->SetUniform_ColorModulate(CGEN_CONST, AGEN_CONST);
|
||
|
|
||
|
// u_Color
|
||
|
gl_genericShader->SetUniform_Color(colorRed);
|
||
|
|
||
|
gl_genericShader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_genericShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_genericShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_genericShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_genericShader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(tr.whiteImage);
|
||
|
//gl_genericShader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
gl_genericShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
R_BindFBO(previousFBO);
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
GLimp_LogComment("--- HEATHAZE FIX END ---\n");
|
||
|
}
|
||
|
|
||
|
// remove alpha test
|
||
|
stateBits = pStage->stateBits;
|
||
|
stateBits &= ~GLS_ATEST_BITS;
|
||
|
stateBits &= ~GLS_DEPTHMASK_TRUE;
|
||
|
|
||
|
GL_State(stateBits);
|
||
|
|
||
|
// choose right shader program ----------------------------------
|
||
|
gl_heatHazeShader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
//gl_heatHazeShader->SetAlphaTesting((pStage->stateBits & GLS_ATEST_BITS) != 0);
|
||
|
|
||
|
gl_heatHazeShader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_heatHazeShader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_heatHazeShader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_heatHazeShader->BindProgram();
|
||
|
|
||
|
// end choose right shader program ------------------------------
|
||
|
|
||
|
// set uniforms
|
||
|
//GLSL_SetUniform_AlphaTest(&tr.heatHazeShader, pStage->stateBits);
|
||
|
|
||
|
deformMagnitude = RB_EvalExpression(&pStage->deformMagnitudeExp, 1.0);
|
||
|
gl_heatHazeShader->SetUniform_DeformMagnitude(deformMagnitude);
|
||
|
|
||
|
gl_heatHazeShader->SetUniform_ModelViewMatrixTranspose(glState.modelViewMatrix[glState.stackIndex]);
|
||
|
gl_heatHazeShader->SetUniform_ProjectionMatrixTranspose(glState.projectionMatrix[glState.stackIndex]);
|
||
|
gl_heatHazeShader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_heatHazeShader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_heatHazeShader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_heatHazeShader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_heatHazeShader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
gl_heatHazeShader->SetUniform_NormalTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
// bind u_CurrentMap
|
||
|
GL_SelectTexture(1);
|
||
|
if(DS_STANDARD_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.deferredRenderFBOImage);
|
||
|
}
|
||
|
else if(HDR_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.deferredRenderFBOImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.currentRenderImage);
|
||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderImage->uploadWidth, tr.currentRenderImage->uploadHeight);
|
||
|
}
|
||
|
|
||
|
// bind u_ContrastMap
|
||
|
if(r_heatHazeFix->integer && glConfig2.framebufferBlitAvailable /*&& glConfig.hardwareType != GLHW_ATI && glConfig.hardwareType != GLHW_ATI_DX10*/ && glConfig.driverType != GLDRV_MESA)
|
||
|
{
|
||
|
GL_SelectTexture(2);
|
||
|
GL_Bind(tr.occlusionRenderFBOImage);
|
||
|
}
|
||
|
|
||
|
gl_heatHazeShader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
static void Render_liquid(int stage)
|
||
|
{
|
||
|
#if !defined(GLSL_COMPILE_STARTUP_ONLY)
|
||
|
vec3_t viewOrigin;
|
||
|
float fogDensity;
|
||
|
vec3_t fogColor;
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
GLimp_LogComment("--- Render_liquid ---\n");
|
||
|
|
||
|
// Tr3B: don't allow blend effects
|
||
|
GL_State(pStage->stateBits & ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE));
|
||
|
|
||
|
// enable shader, set arrays
|
||
|
GL_BindProgram(&tr.liquidShader);
|
||
|
GL_VertexAttribsState(tr.liquidShader.attribs);
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin); // in world space
|
||
|
|
||
|
fogDensity = RB_EvalExpression(&pStage->fogDensityExp, 0.001);
|
||
|
VectorCopy(tess.svars.color, fogColor);
|
||
|
|
||
|
GLSL_SetUniform_ViewOrigin(&tr.liquidShader, viewOrigin);
|
||
|
GLSL_SetUniform_RefractionIndex(&tr.liquidShader, RB_EvalExpression(&pStage->refractionIndexExp, 1.0));
|
||
|
glUniform1fARB(tr.liquidShader.u_FresnelPower, RB_EvalExpression(&pStage->fresnelPowerExp, 2.0));
|
||
|
glUniform1fARB(tr.liquidShader.u_FresnelScale, RB_EvalExpression(&pStage->fresnelScaleExp, 1.0));
|
||
|
glUniform1fARB(tr.liquidShader.u_FresnelBias, RB_EvalExpression(&pStage->fresnelBiasExp, 0.05));
|
||
|
glUniform1fARB(tr.liquidShader.u_NormalScale, RB_EvalExpression(&pStage->normalScaleExp, 0.05));
|
||
|
glUniform1fARB(tr.liquidShader.u_FogDensity, fogDensity);
|
||
|
glUniform3fARB(tr.liquidShader.u_FogColor, fogColor[0], fogColor[1], fogColor[2]);
|
||
|
|
||
|
GLSL_SetUniform_UnprojectMatrix(&tr.liquidShader, backEnd.viewParms.unprojectionMatrix);
|
||
|
GLSL_SetUniform_ModelMatrix(&tr.liquidShader, backEnd.orientation.transformMatrix);
|
||
|
GLSL_SetUniform_ModelViewProjectionMatrix(&tr.liquidShader, glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// capture current color buffer for u_CurrentMap
|
||
|
GL_SelectTexture(0);
|
||
|
if(DS_STANDARD_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.deferredRenderFBOImage);
|
||
|
}
|
||
|
else if(HDR_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.deferredRenderFBOImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_Bind(tr.currentRenderImage);
|
||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.currentRenderImage->uploadWidth, tr.currentRenderImage->uploadHeight);
|
||
|
}
|
||
|
|
||
|
// bind u_PortalMap
|
||
|
GL_SelectTexture(1);
|
||
|
GL_Bind(tr.portalRenderImage);
|
||
|
|
||
|
// bind u_DepthMap
|
||
|
GL_SelectTexture(2);
|
||
|
if(DS_STANDARD_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
}
|
||
|
else if(HDR_ENABLED())
|
||
|
{
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// depth texture is not bound to a FBO
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.depthRenderImage->uploadWidth, tr.depthRenderImage->uploadHeight);
|
||
|
}
|
||
|
|
||
|
// bind u_NormalMap
|
||
|
GL_SelectTexture(3);
|
||
|
GL_Bind(pStage->bundle[TB_COLORMAP].image[0]);
|
||
|
GLSL_SetUniform_NormalTextureMatrix(&tr.liquidShader, tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
static void Render_fog()
|
||
|
{
|
||
|
fog_t *fog;
|
||
|
float eyeT;
|
||
|
qboolean eyeOutside;
|
||
|
vec3_t local;
|
||
|
vec4_t fogDistanceVector, fogDepthVector;
|
||
|
|
||
|
//ri.Printf(PRINT_ALL, "--- Render_fog ---\n");
|
||
|
|
||
|
#if defined(COMPAT_ET)
|
||
|
// no fog pass in snooper
|
||
|
if((tr.refdef.rdflags & RDF_SNOOPERVIEW) || tess.surfaceShader->noFog || !r_wolfFog->integer)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// ydnar: no world, no fogging
|
||
|
if(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(tr.world->fogs == 0) {
|
||
|
ri.Printf(PRINT_WARNING,"Render_fog called on map without fogs\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
fog = tr.world->fogs + tess.fogNum;
|
||
|
|
||
|
// Tr3B: use this only to render fog brushes
|
||
|
#if 1
|
||
|
if(fog->originalBrushNumber < 0 && tess.surfaceShader->sort <= SS_OPAQUE)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if(r_logFile->integer)
|
||
|
{
|
||
|
GLimp_LogComment(va("--- Render_fog( fogNum = %i, originalBrushNumber = %i ) ---\n", tess.fogNum, fog->originalBrushNumber));
|
||
|
}
|
||
|
|
||
|
// all fogging distance is based on world Z units
|
||
|
VectorSubtract(backEnd.orientation.origin, backEnd.viewParms.orientation.origin, local);
|
||
|
fogDistanceVector[0] = -backEnd.orientation.modelViewMatrix[2];
|
||
|
fogDistanceVector[1] = -backEnd.orientation.modelViewMatrix[6];
|
||
|
fogDistanceVector[2] = -backEnd.orientation.modelViewMatrix[10];
|
||
|
fogDistanceVector[3] = DotProduct(local, backEnd.viewParms.orientation.axis[0]);
|
||
|
|
||
|
// scale the fog vectors based on the fog's thickness
|
||
|
fogDistanceVector[0] *= fog->tcScale;
|
||
|
fogDistanceVector[1] *= fog->tcScale;
|
||
|
fogDistanceVector[2] *= fog->tcScale;
|
||
|
fogDistanceVector[3] *= fog->tcScale;
|
||
|
|
||
|
// rotate the gradient vector for this orientation
|
||
|
if(fog->hasSurface)
|
||
|
{
|
||
|
fogDepthVector[0] = fog->surface[0] * backEnd.orientation.axis[0][0] +
|
||
|
fog->surface[1] * backEnd.orientation.axis[0][1] + fog->surface[2] * backEnd.orientation.axis[0][2];
|
||
|
fogDepthVector[1] = fog->surface[0] * backEnd.orientation.axis[1][0] +
|
||
|
fog->surface[1] * backEnd.orientation.axis[1][1] + fog->surface[2] * backEnd.orientation.axis[1][2];
|
||
|
fogDepthVector[2] = fog->surface[0] * backEnd.orientation.axis[2][0] +
|
||
|
fog->surface[1] * backEnd.orientation.axis[2][1] + fog->surface[2] * backEnd.orientation.axis[2][2];
|
||
|
fogDepthVector[3] = -fog->surface[3] + DotProduct(backEnd.orientation.origin, fog->surface);
|
||
|
|
||
|
eyeT = DotProduct(backEnd.orientation.viewOrigin, fogDepthVector) + fogDepthVector[3];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
eyeT = 1; // non-surface fog always has eye inside
|
||
|
}
|
||
|
|
||
|
// see if the viewpoint is outside
|
||
|
// this is needed for clipping distance even for constant fog
|
||
|
|
||
|
if(eyeT < 0)
|
||
|
{
|
||
|
eyeOutside = qtrue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
eyeOutside = qfalse;
|
||
|
}
|
||
|
|
||
|
fogDistanceVector[3] += 1.0 / 512;
|
||
|
|
||
|
|
||
|
if(tess.surfaceShader->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);
|
||
|
}
|
||
|
|
||
|
gl_fogQuake3Shader->SetPortalClipping(backEnd.viewParms.isPortal);
|
||
|
|
||
|
gl_fogQuake3Shader->SetVertexSkinning(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning);
|
||
|
gl_fogQuake3Shader->SetVertexAnimation(glState.vertexAttribsInterpolation > 0);
|
||
|
|
||
|
gl_fogQuake3Shader->SetDeformVertexes(tess.surfaceShader->numDeforms);
|
||
|
|
||
|
gl_fogQuake3Shader->SetMacro_EYE_OUTSIDE(eyeT < 0);
|
||
|
|
||
|
gl_fogQuake3Shader->BindProgram();
|
||
|
|
||
|
|
||
|
|
||
|
gl_fogQuake3Shader->SetUniform_FogDistanceVector(fogDistanceVector);
|
||
|
gl_fogQuake3Shader->SetUniform_FogDepthVector(fogDepthVector);
|
||
|
gl_fogQuake3Shader->SetUniform_FogEyeT(eyeT);
|
||
|
|
||
|
// u_Color
|
||
|
gl_fogQuake3Shader->SetUniform_Color(fog->color);
|
||
|
|
||
|
gl_fogQuake3Shader->SetUniform_ModelMatrix(backEnd.orientation.transformMatrix);
|
||
|
gl_fogQuake3Shader->SetUniform_ModelViewProjectionMatrix(glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// u_BoneMatrix
|
||
|
if(glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning)
|
||
|
{
|
||
|
gl_fogQuake3Shader->SetUniform_BoneMatrix(MAX_BONES, tess.boneMatrices);
|
||
|
}
|
||
|
|
||
|
// u_VertexInterpolation
|
||
|
if(glState.vertexAttribsInterpolation > 0)
|
||
|
{
|
||
|
gl_fogQuake3Shader->SetUniform_VertexInterpolation(glState.vertexAttribsInterpolation);
|
||
|
}
|
||
|
|
||
|
// u_DeformGen
|
||
|
if(tess.surfaceShader->numDeforms)
|
||
|
{
|
||
|
gl_fogQuake3Shader->SetUniform_DeformParms(tess.surfaceShader->deforms, tess.surfaceShader->numDeforms);
|
||
|
gl_fogQuake3Shader->SetUniform_Time(backEnd.refdef.floatTime);
|
||
|
}
|
||
|
|
||
|
if(backEnd.viewParms.isPortal)
|
||
|
{
|
||
|
float plane[4];
|
||
|
|
||
|
// clipping plane in world space
|
||
|
plane[0] = backEnd.viewParms.portalPlane.normal[0];
|
||
|
plane[1] = backEnd.viewParms.portalPlane.normal[1];
|
||
|
plane[2] = backEnd.viewParms.portalPlane.normal[2];
|
||
|
plane[3] = backEnd.viewParms.portalPlane.dist;
|
||
|
|
||
|
gl_fogQuake3Shader->SetUniform_PortalPlane(plane);
|
||
|
}
|
||
|
|
||
|
// bind u_ColorMap
|
||
|
GL_SelectTexture(0);
|
||
|
GL_Bind(tr.fogImage);
|
||
|
//gl_fogQuake3Shader->SetUniform_ColorTextureMatrix(tess.svars.texMatrices[TB_COLORMAP]);
|
||
|
|
||
|
gl_fogQuake3Shader->SetRequiredVertexPointers();
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// see Fog Polygon Volumes documentation by Nvidia for further information
|
||
|
static void Render_volumetricFog()
|
||
|
{
|
||
|
#if 0
|
||
|
vec3_t viewOrigin;
|
||
|
float fogDensity;
|
||
|
vec3_t fogColor;
|
||
|
|
||
|
GLimp_LogComment("--- Render_volumetricFog---\n");
|
||
|
|
||
|
if(glConfig2.framebufferBlitAvailable)
|
||
|
{
|
||
|
FBO_t *previousFBO;
|
||
|
|
||
|
previousFBO = glState.currentFBO;
|
||
|
|
||
|
if(r_deferredShading->integer && glConfig2.framebufferObjectAvailable && glConfig2.textureFloatAvailable &&
|
||
|
glConfig2.drawBuffersAvailable && glConfig2.maxDrawBuffers >= 4)
|
||
|
{
|
||
|
// copy deferredRenderFBO to occlusionRenderFBO
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, tr.deferredRenderFBO->width, tr.deferredRenderFBO->height,
|
||
|
0, 0, tr.occlusionRenderFBO->width, tr.occlusionRenderFBO->height,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
}
|
||
|
else if(r_hdrRendering->integer && glConfig2.framebufferObjectAvailable && glConfig2.textureFloatAvailable)
|
||
|
{
|
||
|
// copy deferredRenderFBO to occlusionRenderFBO
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, tr.deferredRenderFBO->frameBuffer);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, tr.deferredRenderFBO->width, tr.deferredRenderFBO->height,
|
||
|
0, 0, tr.occlusionRenderFBO->width, tr.occlusionRenderFBO->height,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// copy depth of the main context to occlusionRenderFBO
|
||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
|
||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, tr.occlusionRenderFBO->frameBuffer);
|
||
|
glBlitFramebufferEXT(0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
0, 0, glConfig.vidWidth, glConfig.vidHeight,
|
||
|
GL_DEPTH_BUFFER_BIT,
|
||
|
GL_NEAREST);
|
||
|
}
|
||
|
|
||
|
// setup shader with uniforms
|
||
|
GL_BindProgram(&tr.depthToColorShader);
|
||
|
GL_VertexAttribsState(tr.depthToColorShader.attribs);
|
||
|
GL_State(0);//GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
||
|
|
||
|
GLSL_SetUniform_ModelViewProjectionMatrix(&tr.depthToColorShader, glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
|
||
|
// Tr3B: might be cool for ghost player effects
|
||
|
if(glConfig2.vboVertexSkinningAvailable)
|
||
|
{
|
||
|
GLSL_SetUniform_VertexSkinning(&tr.depthToColorShader, tess.vboVertexSkinning);
|
||
|
|
||
|
if(tess.vboVertexSkinning)
|
||
|
glUniformMatrix4fvARB(tr.depthToColorShader.u_BoneMatrix, MAX_BONES, GL_FALSE, &tess.boneMatrices[0][0]);
|
||
|
}
|
||
|
|
||
|
|
||
|
// render back faces
|
||
|
R_BindFBO(tr.occlusionRenderFBO);
|
||
|
R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.depthToColorBackFacesFBOImage->texnum, 0);
|
||
|
|
||
|
GL_ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||
|
GL_Cull(CT_BACK_SIDED);
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
// render front faces
|
||
|
R_AttachFBOTexture2D(GL_TEXTURE_2D, tr.depthToColorFrontFacesFBOImage->texnum, 0);
|
||
|
|
||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||
|
GL_Cull(CT_FRONT_SIDED);
|
||
|
Tess_DrawElements();
|
||
|
|
||
|
R_BindFBO(previousFBO);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// enable shader, set arrays
|
||
|
GL_BindProgram(&tr.volumetricFogShader);
|
||
|
GL_VertexAttribsState(tr.volumetricFogShader.attribs);
|
||
|
|
||
|
//GL_State(GLS_DEPTHTEST_DISABLE); // | GLS_DEPTHMASK_TRUE);
|
||
|
//GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
|
||
|
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_SRC_ALPHA);
|
||
|
GL_Cull(CT_TWO_SIDED);
|
||
|
|
||
|
glVertexAttrib4fvARB(ATTR_INDEX_COLOR, colorWhite);
|
||
|
|
||
|
// set uniforms
|
||
|
VectorCopy(backEnd.viewParms.orientation.origin, viewOrigin); // in world space
|
||
|
|
||
|
{
|
||
|
fogDensity = tess.surfaceShader->fogParms.density;
|
||
|
VectorCopy(tess.surfaceShader->fogParms.color, fogColor);
|
||
|
}
|
||
|
|
||
|
GLSL_SetUniform_ModelViewProjectionMatrix(&tr.volumetricFogShader, glState.modelViewProjectionMatrix[glState.stackIndex]);
|
||
|
GLSL_SetUniform_UnprojectMatrix(&tr.volumetricFogShader, backEnd.viewParms.unprojectionMatrix);
|
||
|
|
||
|
GLSL_SetUniform_ViewOrigin(&tr.volumetricFogShader, viewOrigin);
|
||
|
glUniform1fARB(tr.volumetricFogShader.u_FogDensity, fogDensity);
|
||
|
glUniform3fARB(tr.volumetricFogShader.u_FogColor, fogColor[0], fogColor[1], fogColor[2]);
|
||
|
|
||
|
// bind u_DepthMap
|
||
|
GL_SelectTexture(0);
|
||
|
if(r_deferredShading->integer && glConfig2.framebufferObjectAvailable && glConfig2.textureFloatAvailable &&
|
||
|
glConfig2.drawBuffersAvailable && glConfig2.maxDrawBuffers >= 4)
|
||
|
{
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
}
|
||
|
else if(r_hdrRendering->integer && glConfig2.framebufferObjectAvailable && glConfig2.textureFloatAvailable)
|
||
|
{
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// depth texture is not bound to a FBO
|
||
|
GL_Bind(tr.depthRenderImage);
|
||
|
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, tr.depthRenderImage->uploadWidth, tr.depthRenderImage->uploadHeight);
|
||
|
}
|
||
|
|
||
|
// bind u_DepthMapBack
|
||
|
GL_SelectTexture(1);
|
||
|
GL_Bind(tr.depthToColorBackFacesFBOImage);
|
||
|
|
||
|
// bind u_DepthMapFront
|
||
|
GL_SelectTexture(2);
|
||
|
GL_Bind(tr.depthToColorFrontFacesFBOImage);
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
Tess_ComputeColor
|
||
|
===============
|
||
|
*/
|
||
|
void Tess_ComputeColor(shaderStage_t * pStage)
|
||
|
{
|
||
|
float rgb;
|
||
|
float red;
|
||
|
float green;
|
||
|
float blue;
|
||
|
float alpha;
|
||
|
|
||
|
GLimp_LogComment("--- Tess_ComputeColor ---\n");
|
||
|
|
||
|
// rgbGen
|
||
|
switch (pStage->rgbGen)
|
||
|
{
|
||
|
case CGEN_IDENTITY:
|
||
|
{
|
||
|
tess.svars.color[0] = 1.0;
|
||
|
tess.svars.color[1] = 1.0;
|
||
|
tess.svars.color[2] = 1.0;
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_VERTEX:
|
||
|
case CGEN_ONE_MINUS_VERTEX:
|
||
|
{
|
||
|
tess.svars.color[0] = 0.0;
|
||
|
tess.svars.color[1] = 0.0;
|
||
|
tess.svars.color[2] = 0.0;
|
||
|
tess.svars.color[3] = 0.0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
case CGEN_IDENTITY_LIGHTING:
|
||
|
{
|
||
|
tess.svars.color[0] = tr.identityLight;
|
||
|
tess.svars.color[1] = tr.identityLight;
|
||
|
tess.svars.color[2] = tr.identityLight;
|
||
|
tess.svars.color[3] = tr.identityLight;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_CONST:
|
||
|
{
|
||
|
tess.svars.color[0] = pStage->constantColor[0] * (1.0 / 255.0);
|
||
|
tess.svars.color[1] = pStage->constantColor[1] * (1.0 / 255.0);
|
||
|
tess.svars.color[2] = pStage->constantColor[2] * (1.0 / 255.0);
|
||
|
tess.svars.color[3] = pStage->constantColor[3] * (1.0 / 255.0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_ENTITY:
|
||
|
{
|
||
|
if(backEnd.currentLight)
|
||
|
{
|
||
|
tess.svars.color[0] = Q_bound(0.0, backEnd.currentLight->l.color[0], 1.0);
|
||
|
tess.svars.color[1] = Q_bound(0.0, backEnd.currentLight->l.color[1], 1.0);
|
||
|
tess.svars.color[2] = Q_bound(0.0, backEnd.currentLight->l.color[2], 1.0);
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
}
|
||
|
else if(backEnd.currentEntity)
|
||
|
{
|
||
|
tess.svars.color[0] = Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[0] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[1] = Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[1] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[2] = Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[2] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[3] = Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[3] * (1.0 / 255.0), 1.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tess.svars.color[0] = 1.0;
|
||
|
tess.svars.color[1] = 1.0;
|
||
|
tess.svars.color[2] = 1.0;
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_ONE_MINUS_ENTITY:
|
||
|
{
|
||
|
if(backEnd.currentLight)
|
||
|
{
|
||
|
tess.svars.color[0] = 1.0 - Q_bound(0.0, backEnd.currentLight->l.color[0], 1.0);
|
||
|
tess.svars.color[1] = 1.0 - Q_bound(0.0, backEnd.currentLight->l.color[1], 1.0);
|
||
|
tess.svars.color[2] = 1.0 - Q_bound(0.0, backEnd.currentLight->l.color[2], 1.0);
|
||
|
tess.svars.color[3] = 0.0; // FIXME
|
||
|
}
|
||
|
else if(backEnd.currentEntity)
|
||
|
{
|
||
|
tess.svars.color[0] = 1.0 - Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[0] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[1] = 1.0 - Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[1] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[2] = 1.0 - Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[2] * (1.0 / 255.0), 1.0);
|
||
|
tess.svars.color[3] = 1.0 - Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[3] * (1.0 / 255.0), 1.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tess.svars.color[0] = 0.0;
|
||
|
tess.svars.color[1] = 0.0;
|
||
|
tess.svars.color[2] = 0.0;
|
||
|
tess.svars.color[3] = 0.0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_WAVEFORM:
|
||
|
{
|
||
|
float glow;
|
||
|
waveForm_t *wf;
|
||
|
|
||
|
wf = &pStage->rgbWave;
|
||
|
|
||
|
if(wf->func == GF_NOISE)
|
||
|
{
|
||
|
glow = wf->base + R_NoiseGet4f(0, 0, 0, (backEnd.refdef.floatTime + wf->phase) * wf->frequency) * wf->amplitude;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
glow = RB_EvalWaveForm(wf) * tr.identityLight;
|
||
|
}
|
||
|
|
||
|
if(glow < 0)
|
||
|
{
|
||
|
glow = 0;
|
||
|
}
|
||
|
else if(glow > 1)
|
||
|
{
|
||
|
glow = 1;
|
||
|
}
|
||
|
|
||
|
tess.svars.color[0] = glow;
|
||
|
tess.svars.color[1] = glow;
|
||
|
tess.svars.color[2] = glow;
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_CUSTOM_RGB:
|
||
|
{
|
||
|
rgb = Q_bound(0.0, RB_EvalExpression(&pStage->rgbExp, 1.0), 1.0);
|
||
|
|
||
|
tess.svars.color[0] = rgb;
|
||
|
tess.svars.color[1] = rgb;
|
||
|
tess.svars.color[2] = rgb;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case CGEN_CUSTOM_RGBs:
|
||
|
{
|
||
|
if(backEnd.currentLight)
|
||
|
{
|
||
|
red = Q_bound(0.0, RB_EvalExpression(&pStage->redExp, backEnd.currentLight->l.color[0]), 1.0);
|
||
|
green = Q_bound(0.0, RB_EvalExpression(&pStage->greenExp, backEnd.currentLight->l.color[1]), 1.0);
|
||
|
blue = Q_bound(0.0, RB_EvalExpression(&pStage->blueExp, backEnd.currentLight->l.color[2]), 1.0);
|
||
|
}
|
||
|
else if(backEnd.currentEntity)
|
||
|
{
|
||
|
red =
|
||
|
Q_bound(0.0, RB_EvalExpression(&pStage->redExp, backEnd.currentEntity->e.shaderRGBA[0] * (1.0 / 255.0)), 1.0);
|
||
|
green =
|
||
|
Q_bound(0.0, RB_EvalExpression(&pStage->greenExp, backEnd.currentEntity->e.shaderRGBA[1] * (1.0 / 255.0)),
|
||
|
1.0);
|
||
|
blue =
|
||
|
Q_bound(0.0, RB_EvalExpression(&pStage->blueExp, backEnd.currentEntity->e.shaderRGBA[2] * (1.0 / 255.0)),
|
||
|
1.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
red = Q_bound(0.0, RB_EvalExpression(&pStage->redExp, 1.0), 1.0);
|
||
|
green = Q_bound(0.0, RB_EvalExpression(&pStage->greenExp, 1.0), 1.0);
|
||
|
blue = Q_bound(0.0, RB_EvalExpression(&pStage->blueExp, 1.0), 1.0);
|
||
|
}
|
||
|
|
||
|
tess.svars.color[0] = red;
|
||
|
tess.svars.color[1] = green;
|
||
|
tess.svars.color[2] = blue;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// alphaGen
|
||
|
switch (pStage->alphaGen)
|
||
|
{
|
||
|
default:
|
||
|
case AGEN_IDENTITY:
|
||
|
{
|
||
|
if(pStage->rgbGen != CGEN_IDENTITY)
|
||
|
{
|
||
|
if((pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1) || pStage->rgbGen != CGEN_VERTEX)
|
||
|
{
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_VERTEX:
|
||
|
case AGEN_ONE_MINUS_VERTEX:
|
||
|
{
|
||
|
tess.svars.color[3] = 0.0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_CONST:
|
||
|
{
|
||
|
if(pStage->rgbGen != CGEN_CONST)
|
||
|
{
|
||
|
tess.svars.color[3] = pStage->constantColor[3] * (1.0 / 255.0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_ENTITY:
|
||
|
{
|
||
|
if(backEnd.currentLight)
|
||
|
{
|
||
|
tess.svars.color[3] = 1.0; // FIXME ?
|
||
|
}
|
||
|
else if(backEnd.currentEntity)
|
||
|
{
|
||
|
tess.svars.color[3] = Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[3] * (1.0 / 255.0), 1.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tess.svars.color[3] = 1.0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_ONE_MINUS_ENTITY:
|
||
|
{
|
||
|
if(backEnd.currentLight)
|
||
|
{
|
||
|
tess.svars.color[3] = 0.0; // FIXME ?
|
||
|
}
|
||
|
else if(backEnd.currentEntity)
|
||
|
{
|
||
|
tess.svars.color[3] = 1.0 - Q_bound(0.0, backEnd.currentEntity->e.shaderRGBA[3] * (1.0 / 255.0), 1.0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tess.svars.color[3] = 0.0;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_WAVEFORM:
|
||
|
{
|
||
|
float glow;
|
||
|
waveForm_t *wf;
|
||
|
|
||
|
wf = &pStage->alphaWave;
|
||
|
|
||
|
glow = RB_EvalWaveFormClamped(wf);
|
||
|
|
||
|
tess.svars.color[3] = glow;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case AGEN_CUSTOM:
|
||
|
{
|
||
|
alpha = Q_bound(0.0, RB_EvalExpression(&pStage->alphaExp, 1.0), 1.0);
|
||
|
|
||
|
tess.svars.color[3] = alpha;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============
|
||
|
Tess_ComputeTexMatrices
|
||
|
===============
|
||
|
*/
|
||
|
static void Tess_ComputeTexMatrices(shaderStage_t * pStage)
|
||
|
{
|
||
|
int i;
|
||
|
vec_t *matrix;
|
||
|
|
||
|
GLimp_LogComment("--- Tess_ComputeTexMatrices ---\n");
|
||
|
|
||
|
for(i = 0; i < MAX_TEXTURE_BUNDLES; i++)
|
||
|
{
|
||
|
matrix = tess.svars.texMatrices[i];
|
||
|
|
||
|
RB_CalcTexMatrix(&pStage->bundle[i], matrix);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==============
|
||
|
SetIteratorFog
|
||
|
set the fog parameters for this pass
|
||
|
==============
|
||
|
*/
|
||
|
#if defined(COMPAT_ET)
|
||
|
static void SetIteratorFog()
|
||
|
{
|
||
|
GLimp_LogComment("--- SetIteratorFog() ---\n");
|
||
|
|
||
|
// changed for problem when you start the game with r_fastsky set to '1'
|
||
|
// if(r_fastsky->integer || backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) {
|
||
|
if(backEnd.refdef.rdflags & RDF_NOWORLDMODEL)
|
||
|
{
|
||
|
RB_FogOff();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(backEnd.refdef.rdflags & RDF_DRAWINGSKY)
|
||
|
{
|
||
|
if(tr.glfogsettings[FOG_SKY].registered)
|
||
|
{
|
||
|
RB_Fog(&tr.glfogsettings[FOG_SKY]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RB_FogOff();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(tr.world && tr.world->hasSkyboxPortal && (backEnd.refdef.rdflags & RDF_SKYBOXPORTAL))
|
||
|
{
|
||
|
if(tr.glfogsettings[FOG_PORTALVIEW].registered)
|
||
|
{
|
||
|
RB_Fog(&tr.glfogsettings[FOG_PORTALVIEW]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RB_FogOff();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(tr.glfogNum > FOG_NONE)
|
||
|
{
|
||
|
RB_Fog(&tr.glfogsettings[FOG_CURRENT]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RB_FogOff();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // #if defined(COMPAT_ET)
|
||
|
|
||
|
|
||
|
void Tess_StageIteratorDebug()
|
||
|
{
|
||
|
// 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("--- Tess_StageIteratorDebug( %i vertices, %i triangles ) ---\n", tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
// Tr3B: FIXME analyze required vertex attribs by the current material
|
||
|
Tess_UpdateVBOs(0);
|
||
|
}
|
||
|
|
||
|
Tess_DrawElements();
|
||
|
}
|
||
|
|
||
|
void Tess_StageIteratorGeneric()
|
||
|
{
|
||
|
int stage;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorGeneric( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
// Tr3B: FIXME analyze required vertex attribs by the current material
|
||
|
Tess_UpdateVBOs(0);
|
||
|
}
|
||
|
|
||
|
// set GL fog
|
||
|
//SetIteratorFog();
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
for(stage = 0; stage < MAX_SHADER_STAGES; stage++)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
if(!pStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&pStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// Ridah, per stage fogging (detail textures)
|
||
|
if(tess.surfaceShader->noFog && pStage->isFogged)
|
||
|
{
|
||
|
RB_FogOn();
|
||
|
}
|
||
|
else if(tess.surfaceShader->noFog && !pStage->isFogged)
|
||
|
{
|
||
|
RB_FogOff();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// make sure it's on
|
||
|
RB_FogOn();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Tess_ComputeColor(pStage);
|
||
|
Tess_ComputeTexMatrices(pStage);
|
||
|
|
||
|
switch (pStage->type)
|
||
|
{
|
||
|
case ST_COLORMAP:
|
||
|
{
|
||
|
Render_generic(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if defined(COMPAT_Q3A) || defined(COMPAT_ET)
|
||
|
case ST_LIGHTMAP:
|
||
|
{
|
||
|
Render_lightMapping(stage, true, false);
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
{
|
||
|
//if(tess.surfaceShader->sort <= SS_OPAQUE)
|
||
|
{
|
||
|
if(r_precomputedLighting->integer || r_vertexLighting->integer)
|
||
|
{
|
||
|
if(!r_vertexLighting->integer && tess.lightmapNum >= 0 && tess.lightmapNum < tr.lightmaps.currentElements)
|
||
|
{
|
||
|
if(tr.worldDeluxeMapping && r_normalMapping->integer)
|
||
|
{
|
||
|
Render_lightMapping(stage, false, true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Render_lightMapping(stage, false, false);
|
||
|
}
|
||
|
}
|
||
|
else if(backEnd.currentEntity != &tr.worldEntity)
|
||
|
{
|
||
|
Render_vertexLighting_DBS_entity(stage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Render_vertexLighting_DBS_world(stage);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Render_depthFill(stage);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_COLLAPSE_reflection_CB:
|
||
|
case ST_REFLECTIONMAP:
|
||
|
{
|
||
|
if(r_reflectionMapping->integer)
|
||
|
Render_reflection_CB(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_REFRACTIONMAP:
|
||
|
{
|
||
|
//Render_refraction_C(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_DISPERSIONMAP:
|
||
|
{
|
||
|
Render_dispersion_C(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_SKYBOXMAP:
|
||
|
{
|
||
|
Render_skybox(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_SCREENMAP:
|
||
|
{
|
||
|
Render_screen(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_PORTALMAP:
|
||
|
{
|
||
|
Render_portal(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
case ST_HEATHAZEMAP:
|
||
|
{
|
||
|
Render_heatHaze(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_LIQUIDMAP:
|
||
|
{
|
||
|
Render_liquid(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if defined(COMPAT_Q3A) || defined(COMPAT_ET)
|
||
|
if(r_showLightMaps->integer && pStage->type == ST_LIGHTMAP)
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if(!r_noFog->integer && tess.fogNum >= 1 && tess.surfaceShader->fogPass)
|
||
|
{
|
||
|
Render_fog();
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Tess_StageIteratorGBuffer()
|
||
|
{
|
||
|
int stage;
|
||
|
bool diffuseRendered = false;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorGBuffer( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
// Tr3B: FIXME analyze required vertex attribs by the current material
|
||
|
Tess_UpdateVBOs(0);
|
||
|
}
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
for(stage = 0; stage < MAX_SHADER_STAGES; stage++)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
if(!pStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&pStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Tess_ComputeColor(pStage);
|
||
|
Tess_ComputeTexMatrices(pStage);
|
||
|
|
||
|
switch (pStage->type)
|
||
|
{
|
||
|
case ST_COLORMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_generic(stage);
|
||
|
|
||
|
if( tess.surfaceShader->sort <= SS_OPAQUE &&
|
||
|
!(pStage->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) &&
|
||
|
!diffuseRendered)
|
||
|
{
|
||
|
glDrawBuffers(4, geometricRenderTargets);
|
||
|
|
||
|
Render_geometricFill(stage, true);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
{
|
||
|
if(r_precomputedLighting->integer || r_vertexLighting->integer)
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(4, geometricRenderTargets);
|
||
|
|
||
|
if(!r_vertexLighting->integer && tess.lightmapNum >= 0 && tess.lightmapNum < tr.lightmaps.currentElements)
|
||
|
{
|
||
|
if(tr.worldDeluxeMapping && r_normalMapping->integer)
|
||
|
{
|
||
|
Render_lightMapping(stage, false, true);
|
||
|
diffuseRendered = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Render_lightMapping(stage, false, false);
|
||
|
diffuseRendered = true;
|
||
|
}
|
||
|
}
|
||
|
else if(backEnd.currentEntity != &tr.worldEntity)
|
||
|
{
|
||
|
Render_vertexLighting_DBS_entity(stage);
|
||
|
diffuseRendered = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Render_vertexLighting_DBS_world(stage);
|
||
|
diffuseRendered = true;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(4, geometricRenderTargets);
|
||
|
|
||
|
Render_geometricFill(stage, false);
|
||
|
diffuseRendered = true;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_COLLAPSE_reflection_CB:
|
||
|
case ST_REFLECTIONMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_reflection_CB(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_REFRACTIONMAP:
|
||
|
{
|
||
|
/*
|
||
|
if(r_deferredShading->integer == DS_STANDARD)
|
||
|
{
|
||
|
|
||
|
R_BindFBO(tr.deferredRenderFBO);
|
||
|
Render_refraction_C(stage);
|
||
|
}
|
||
|
*/
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_DISPERSIONMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_dispersion_C(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_SKYBOXMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(4, geometricRenderTargets);
|
||
|
|
||
|
Render_skybox(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_SCREENMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_screen(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_PORTALMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_portal(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_HEATHAZEMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_heatHaze(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_LIQUIDMAP:
|
||
|
{
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
glDrawBuffers(1, geometricRenderTargets);
|
||
|
|
||
|
Render_liquid(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!r_noFog->integer && tess.fogNum >= 1 && tess.surfaceShader->fogPass)
|
||
|
{
|
||
|
Render_fog();
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Tess_StageIteratorGBufferNormalsOnly()
|
||
|
{
|
||
|
int stage;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorGBufferNormalsOnly( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
// Tr3B: FIXME analyze required vertex attribs by the current material
|
||
|
Tess_UpdateVBOs(0);
|
||
|
}
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
for(stage = 0; stage < MAX_SHADER_STAGES; stage++)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
if(!pStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&pStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//Tess_ComputeColor(pStage);
|
||
|
Tess_ComputeTexMatrices(pStage);
|
||
|
|
||
|
switch (pStage->type)
|
||
|
{
|
||
|
case ST_COLORMAP:
|
||
|
{
|
||
|
#if 1
|
||
|
if( tess.surfaceShader->sort <= SS_OPAQUE &&
|
||
|
!(pStage->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS)) &&
|
||
|
(pStage->stateBits & (GLS_DEPTHMASK_TRUE))
|
||
|
)
|
||
|
{
|
||
|
#if defined(OFFSCREEN_PREPASS_LIGHTING)
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
#else
|
||
|
R_BindNullFBO();
|
||
|
#endif
|
||
|
Render_geometricFill(stage, true);
|
||
|
}
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
{
|
||
|
#if defined(OFFSCREEN_PREPASS_LIGHTING)
|
||
|
R_BindFBO(tr.geometricRenderFBO);
|
||
|
#else
|
||
|
R_BindNullFBO();
|
||
|
#endif
|
||
|
|
||
|
Render_geometricFill(stage, false);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Tess_StageIteratorDepthFill()
|
||
|
{
|
||
|
int stage;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorDepthFill( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
Tess_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD);
|
||
|
}
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
for(stage = 0; stage < MAX_SHADER_STAGES; stage++)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
if(!pStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&pStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Tess_ComputeTexMatrices(pStage);
|
||
|
|
||
|
switch (pStage->type)
|
||
|
{
|
||
|
case ST_COLORMAP:
|
||
|
{
|
||
|
if(tess.surfaceShader->sort <= SS_OPAQUE)
|
||
|
{
|
||
|
Render_depthFill(stage);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if defined(COMPAT_Q3A) || defined(COMPAT_ET)
|
||
|
case ST_LIGHTMAP:
|
||
|
{
|
||
|
Render_depthFill(stage);
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
{
|
||
|
Render_depthFill(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
|
||
|
void Tess_StageIteratorShadowFill()
|
||
|
{
|
||
|
int stage;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorShadowFill( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
Tess_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD);
|
||
|
}
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
for(stage = 0; stage < MAX_SHADER_STAGES; stage++)
|
||
|
{
|
||
|
shaderStage_t *pStage = tess.surfaceStages[stage];
|
||
|
|
||
|
if(!pStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&pStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Tess_ComputeTexMatrices(pStage);
|
||
|
|
||
|
switch (pStage->type)
|
||
|
{
|
||
|
case ST_COLORMAP:
|
||
|
{
|
||
|
if(tess.surfaceShader->sort <= SS_OPAQUE)
|
||
|
{
|
||
|
Render_shadowFill(stage);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if defined(COMPAT_Q3A) || defined(COMPAT_ET)
|
||
|
case ST_LIGHTMAP:
|
||
|
#endif
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
{
|
||
|
Render_shadowFill(stage);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
|
||
|
void Tess_StageIteratorLighting()
|
||
|
{
|
||
|
int i, j;
|
||
|
trRefLight_t *light;
|
||
|
shaderStage_t *attenuationXYStage;
|
||
|
shaderStage_t *attenuationZStage;
|
||
|
|
||
|
// 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
|
||
|
("--- Tess_StageIteratorLighting( %s, %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name,
|
||
|
tess.lightShader->name, tess.numVertexes, tess.numIndexes / 3));
|
||
|
}
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
light = backEnd.currentLight;
|
||
|
|
||
|
Tess_DeformGeometry();
|
||
|
|
||
|
if(!glState.currentVBO || !glState.currentIBO || glState.currentVBO == tess.vbo || glState.currentIBO == tess.ibo)
|
||
|
{
|
||
|
// Tr3B: FIXME analyze required vertex attribs by the current material
|
||
|
Tess_UpdateVBOs(0);
|
||
|
}
|
||
|
|
||
|
// set OpenGL state for lighting
|
||
|
if(light->l.inverseShadows)
|
||
|
{
|
||
|
GL_State(GLS_SRCBLEND_ZERO | GLS_DSTBLEND_ONE_MINUS_SRC_COLOR);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(tess.surfaceShader->sort > SS_OPAQUE)
|
||
|
{
|
||
|
GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set face culling appropriately
|
||
|
GL_Cull(tess.surfaceShader->cullType);
|
||
|
|
||
|
// set polygon offset if necessary
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||
|
GL_PolygonOffset(r_offsetFactor->value, r_offsetUnits->value);
|
||
|
}
|
||
|
|
||
|
// call shader function
|
||
|
attenuationZStage = tess.lightShader->stages[0];
|
||
|
|
||
|
for(i = 0; i < MAX_SHADER_STAGES; i++)
|
||
|
{
|
||
|
shaderStage_t *diffuseStage = tess.surfaceStages[i];
|
||
|
|
||
|
if(!diffuseStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&diffuseStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Tess_ComputeTexMatrices(diffuseStage);
|
||
|
|
||
|
for(j = 1; j < MAX_SHADER_STAGES; j++)
|
||
|
{
|
||
|
attenuationXYStage = tess.lightShader->stages[j];
|
||
|
|
||
|
if(!attenuationXYStage)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(attenuationXYStage->type != ST_ATTENUATIONMAP_XY)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(!RB_EvalExpression(&attenuationXYStage->ifExp, 1.0))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Tess_ComputeColor(attenuationXYStage);
|
||
|
R_ComputeFinalAttenuation(attenuationXYStage, light);
|
||
|
|
||
|
switch (diffuseStage->type)
|
||
|
{
|
||
|
case ST_DIFFUSEMAP:
|
||
|
case ST_COLLAPSE_lighting_DB:
|
||
|
case ST_COLLAPSE_lighting_DBS:
|
||
|
if(light->l.rlType == RL_OMNI)
|
||
|
{
|
||
|
Render_forwardLighting_DBS_omni(diffuseStage, attenuationXYStage, attenuationZStage, light);
|
||
|
}
|
||
|
else if(light->l.rlType == RL_PROJ)
|
||
|
{
|
||
|
if(!light->l.inverseShadows)
|
||
|
{
|
||
|
Render_forwardLighting_DBS_proj(diffuseStage, attenuationXYStage, attenuationZStage, light);
|
||
|
}
|
||
|
}
|
||
|
else if(light->l.rlType == RL_DIRECTIONAL)
|
||
|
{
|
||
|
//if(!light->l.inverseShadows)
|
||
|
{
|
||
|
Render_forwardLighting_DBS_directional(diffuseStage, attenuationXYStage, attenuationZStage, light);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reset polygon offset
|
||
|
if(tess.surfaceShader->polygonOffset)
|
||
|
{
|
||
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
=================
|
||
|
Tess_End
|
||
|
|
||
|
Render tesselated data
|
||
|
=================
|
||
|
*/
|
||
|
void Tess_End()
|
||
|
{
|
||
|
if((tess.numIndexes == 0 || tess.numVertexes == 0) && tess.multiDrawPrimitives == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(tess.indexes[SHADER_MAX_INDEXES - 1] != 0)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "Tess_End() - SHADER_MAX_INDEXES hit");
|
||
|
}
|
||
|
if(tess.xyz[SHADER_MAX_VERTEXES - 1][0] != 0)
|
||
|
{
|
||
|
ri.Error(ERR_DROP, "Tess_End() - SHADER_MAX_VERTEXES hit");
|
||
|
}
|
||
|
|
||
|
// for debugging of sort order issues, stop rendering after a given sort value
|
||
|
if(r_debugSort->integer && r_debugSort->integer < tess.surfaceShader->sort)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// update performance counter
|
||
|
backEnd.pc.c_batches++;
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
|
||
|
// call off to shader specific tess end function
|
||
|
tess.stageIteratorFunc();
|
||
|
|
||
|
if( (tess.stageIteratorFunc != Tess_StageIteratorShadowFill) &&
|
||
|
(tess.stageIteratorFunc != Tess_StageIteratorDebug))
|
||
|
{
|
||
|
// draw debugging stuff
|
||
|
if(r_showTris->integer || r_showBatches->integer || (r_showLightBatches->integer && (tess.stageIteratorFunc == Tess_StageIteratorLighting)))
|
||
|
{
|
||
|
DrawTris();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tess.vboVertexSkinning = qfalse;
|
||
|
|
||
|
// clear shader so we can tell we don't have any unclosed surfaces
|
||
|
tess.multiDrawPrimitives = 0;
|
||
|
tess.numIndexes = 0;
|
||
|
tess.numVertexes = 0;
|
||
|
|
||
|
GLimp_LogComment("--- Tess_End ---\n");
|
||
|
|
||
|
GL_CheckErrors();
|
||
|
}
|