openmohaa/code/renderer_gl3/tr_shade.cpp

5551 lines
154 KiB
C++
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
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();
}