RenderProgs.cpp (15390B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 #include "tr_local.h" 33 34 35 36 idRenderProgManager renderProgManager; 37 38 /* 39 ================================================================================================ 40 idRenderProgManager::idRenderProgManager() 41 ================================================================================================ 42 */ 43 idRenderProgManager::idRenderProgManager() { 44 } 45 46 /* 47 ================================================================================================ 48 idRenderProgManager::~idRenderProgManager() 49 ================================================================================================ 50 */ 51 idRenderProgManager::~idRenderProgManager() { 52 } 53 54 /* 55 ================================================================================================ 56 R_ReloadShaders 57 ================================================================================================ 58 */ 59 static void R_ReloadShaders( const idCmdArgs &args ) { 60 renderProgManager.KillAllShaders(); 61 renderProgManager.LoadAllShaders(); 62 } 63 64 /* 65 ================================================================================================ 66 idRenderProgManager::Init() 67 ================================================================================================ 68 */ 69 void idRenderProgManager::Init() { 70 common->Printf( "----- Initializing Render Shaders -----\n" ); 71 72 73 for ( int i = 0; i < MAX_BUILTINS; i++ ) { 74 builtinShaders[i] = -1; 75 } 76 struct builtinShaders_t { 77 int index; 78 const char * name; 79 } builtins[] = { 80 { BUILTIN_GUI, "gui.vfp" }, 81 { BUILTIN_COLOR, "color.vfp" }, 82 { BUILTIN_SIMPLESHADE, "simpleshade.vfp" }, 83 { BUILTIN_TEXTURED, "texture.vfp" }, 84 { BUILTIN_TEXTURE_VERTEXCOLOR, "texture_color.vfp" }, 85 { BUILTIN_TEXTURE_VERTEXCOLOR_SKINNED, "texture_color_skinned.vfp" }, 86 { BUILTIN_TEXTURE_TEXGEN_VERTEXCOLOR, "texture_color_texgen.vfp" }, 87 { BUILTIN_INTERACTION, "interaction.vfp" }, 88 { BUILTIN_INTERACTION_SKINNED, "interaction_skinned.vfp" }, 89 { BUILTIN_INTERACTION_AMBIENT, "interactionAmbient.vfp" }, 90 { BUILTIN_INTERACTION_AMBIENT_SKINNED, "interactionAmbient_skinned.vfp" }, 91 { BUILTIN_ENVIRONMENT, "environment.vfp" }, 92 { BUILTIN_ENVIRONMENT_SKINNED, "environment_skinned.vfp" }, 93 { BUILTIN_BUMPY_ENVIRONMENT, "bumpyEnvironment.vfp" }, 94 { BUILTIN_BUMPY_ENVIRONMENT_SKINNED, "bumpyEnvironment_skinned.vfp" }, 95 96 { BUILTIN_DEPTH, "depth.vfp" }, 97 { BUILTIN_DEPTH_SKINNED, "depth_skinned.vfp" }, 98 { BUILTIN_SHADOW_DEBUG, "shadowDebug.vfp" }, 99 { BUILTIN_SHADOW_DEBUG_SKINNED, "shadowDebug_skinned.vfp" }, 100 101 { BUILTIN_BLENDLIGHT, "blendlight.vfp" }, 102 { BUILTIN_FOG, "fog.vfp" }, 103 { BUILTIN_FOG_SKINNED, "fog_skinned.vfp" }, 104 { BUILTIN_SKYBOX, "skybox.vfp" }, 105 { BUILTIN_WOBBLESKY, "wobblesky.vfp" }, 106 { BUILTIN_POSTPROCESS, "postprocess.vfp" }, 107 { BUILTIN_STEREO_DEGHOST, "stereoDeGhost.vfp" }, 108 { BUILTIN_STEREO_WARP, "stereoWarp.vfp" }, 109 { BUILTIN_ZCULL_RECONSTRUCT, "zcullReconstruct.vfp" }, 110 { BUILTIN_BINK, "bink.vfp" }, 111 { BUILTIN_BINK_GUI, "bink_gui.vfp" }, 112 { BUILTIN_STEREO_INTERLACE, "stereoInterlace.vfp" }, 113 { BUILTIN_MOTION_BLUR, "motionBlur.vfp" }, 114 }; 115 int numBuiltins = sizeof( builtins ) / sizeof( builtins[0] ); 116 vertexShaders.SetNum( numBuiltins ); 117 fragmentShaders.SetNum( numBuiltins ); 118 glslPrograms.SetNum( numBuiltins ); 119 120 for ( int i = 0; i < numBuiltins; i++ ) { 121 vertexShaders[i].name = builtins[i].name; 122 fragmentShaders[i].name = builtins[i].name; 123 builtinShaders[builtins[i].index] = i; 124 LoadVertexShader( i ); 125 LoadFragmentShader( i ); 126 LoadGLSLProgram( i, i, i ); 127 } 128 129 // Special case handling for fastZ shaders 130 builtinShaders[BUILTIN_SHADOW] = FindVertexShader( "shadow.vp" ); 131 builtinShaders[BUILTIN_SHADOW_SKINNED] = FindVertexShader( "shadow_skinned.vp" ); 132 133 FindGLSLProgram( "shadow.vp", builtinShaders[BUILTIN_SHADOW], -1 ); 134 FindGLSLProgram( "shadow_skinned.vp", builtinShaders[BUILTIN_SHADOW_SKINNED], -1 ); 135 136 glslUniforms.SetNum( RENDERPARM_USER + MAX_GLSL_USER_PARMS, vec4_zero ); 137 138 vertexShaders[builtinShaders[BUILTIN_TEXTURE_VERTEXCOLOR_SKINNED]].usesJoints = true; 139 vertexShaders[builtinShaders[BUILTIN_INTERACTION_SKINNED]].usesJoints = true; 140 vertexShaders[builtinShaders[BUILTIN_INTERACTION_AMBIENT_SKINNED]].usesJoints = true; 141 vertexShaders[builtinShaders[BUILTIN_ENVIRONMENT_SKINNED]].usesJoints = true; 142 vertexShaders[builtinShaders[BUILTIN_BUMPY_ENVIRONMENT_SKINNED]].usesJoints = true; 143 vertexShaders[builtinShaders[BUILTIN_DEPTH_SKINNED]].usesJoints = true; 144 vertexShaders[builtinShaders[BUILTIN_SHADOW_SKINNED]].usesJoints = true; 145 vertexShaders[builtinShaders[BUILTIN_SHADOW_DEBUG_SKINNED]].usesJoints = true; 146 vertexShaders[builtinShaders[BUILTIN_FOG_SKINNED]].usesJoints = true; 147 148 cmdSystem->AddCommand( "reloadShaders", R_ReloadShaders, CMD_FL_RENDERER, "reloads shaders" ); 149 } 150 151 /* 152 ================================================================================================ 153 idRenderProgManager::LoadAllShaders() 154 ================================================================================================ 155 */ 156 void idRenderProgManager::LoadAllShaders() { 157 for ( int i = 0; i < vertexShaders.Num(); i++ ) { 158 LoadVertexShader( i ); 159 } 160 for ( int i = 0; i < fragmentShaders.Num(); i++ ) { 161 LoadFragmentShader( i ); 162 } 163 164 for ( int i = 0; i < glslPrograms.Num(); ++i ) { 165 LoadGLSLProgram( i, glslPrograms[i].vertexShaderIndex, glslPrograms[i].fragmentShaderIndex ); 166 } 167 } 168 169 /* 170 ================================================================================================ 171 idRenderProgManager::KillAllShaders() 172 ================================================================================================ 173 */ 174 void idRenderProgManager::KillAllShaders() { 175 Unbind(); 176 for ( int i = 0; i < vertexShaders.Num(); i++ ) { 177 if ( vertexShaders[i].progId != INVALID_PROGID ) { 178 qglDeleteShader( vertexShaders[i].progId ); 179 vertexShaders[i].progId = INVALID_PROGID; 180 } 181 } 182 for ( int i = 0; i < fragmentShaders.Num(); i++ ) { 183 if ( fragmentShaders[i].progId != INVALID_PROGID ) { 184 qglDeleteShader( fragmentShaders[i].progId ); 185 fragmentShaders[i].progId = INVALID_PROGID; 186 } 187 } 188 for ( int i = 0; i < glslPrograms.Num(); ++i ) { 189 if ( glslPrograms[i].progId != INVALID_PROGID ) { 190 qglDeleteProgram( glslPrograms[i].progId ); 191 glslPrograms[i].progId = INVALID_PROGID; 192 } 193 } 194 } 195 196 /* 197 ================================================================================================ 198 idRenderProgManager::Shutdown() 199 ================================================================================================ 200 */ 201 void idRenderProgManager::Shutdown() { 202 KillAllShaders(); 203 } 204 205 /* 206 ================================================================================================ 207 idRenderProgManager::FindVertexShader 208 ================================================================================================ 209 */ 210 int idRenderProgManager::FindVertexShader( const char * name ) { 211 for ( int i = 0; i < vertexShaders.Num(); i++ ) { 212 if ( vertexShaders[i].name.Icmp( name ) == 0 ) { 213 LoadVertexShader( i ); 214 return i; 215 } 216 } 217 vertexShader_t shader; 218 shader.name = name; 219 int index = vertexShaders.Append( shader ); 220 LoadVertexShader( index ); 221 currentVertexShader = index; 222 223 // FIXME: we should really scan the program source code for using rpEnableSkinning but at this 224 // point we directly load a binary and the program source code is not available on the consoles 225 if ( idStr::Icmp( name, "heatHaze.vfp" ) == 0 || 226 idStr::Icmp( name, "heatHazeWithMask.vfp" ) == 0 || 227 idStr::Icmp( name, "heatHazeWithMaskAndVertex.vfp" ) == 0 ) { 228 vertexShaders[index].usesJoints = true; 229 vertexShaders[index].optionalSkinning = true; 230 } 231 232 return index; 233 } 234 235 /* 236 ================================================================================================ 237 idRenderProgManager::FindFragmentShader 238 ================================================================================================ 239 */ 240 int idRenderProgManager::FindFragmentShader( const char * name ) { 241 for ( int i = 0; i < fragmentShaders.Num(); i++ ) { 242 if ( fragmentShaders[i].name.Icmp( name ) == 0 ) { 243 LoadFragmentShader( i ); 244 return i; 245 } 246 } 247 fragmentShader_t shader; 248 shader.name = name; 249 int index = fragmentShaders.Append( shader ); 250 LoadFragmentShader( index ); 251 currentFragmentShader = index; 252 return index; 253 } 254 255 256 257 258 /* 259 ================================================================================================ 260 idRenderProgManager::LoadVertexShader 261 ================================================================================================ 262 */ 263 void idRenderProgManager::LoadVertexShader( int index ) { 264 if ( vertexShaders[index].progId != INVALID_PROGID ) { 265 return; // Already loaded 266 } 267 vertexShaders[index].progId = ( GLuint ) LoadGLSLShader( GL_VERTEX_SHADER, vertexShaders[index].name, vertexShaders[index].uniforms ); 268 } 269 270 /* 271 ================================================================================================ 272 idRenderProgManager::LoadFragmentShader 273 ================================================================================================ 274 */ 275 void idRenderProgManager::LoadFragmentShader( int index ) { 276 if ( fragmentShaders[index].progId != INVALID_PROGID ) { 277 return; // Already loaded 278 } 279 fragmentShaders[index].progId = ( GLuint ) LoadGLSLShader( GL_FRAGMENT_SHADER, fragmentShaders[index].name, fragmentShaders[index].uniforms ); 280 } 281 282 /* 283 ================================================================================================ 284 idRenderProgManager::LoadShader 285 ================================================================================================ 286 */ 287 GLuint idRenderProgManager::LoadShader( GLenum target, const char * name, const char * startToken ) { 288 289 idStr fullPath = "renderprogs\\gl\\"; 290 fullPath += name; 291 292 common->Printf( "%s", fullPath.c_str() ); 293 294 char * fileBuffer = NULL; 295 fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL ); 296 if ( fileBuffer == NULL ) { 297 common->Printf( ": File not found\n" ); 298 return INVALID_PROGID; 299 } 300 if ( !R_IsInitialized() ) { 301 common->Printf( ": Renderer not initialized\n" ); 302 fileSystem->FreeFile( fileBuffer ); 303 return INVALID_PROGID; 304 } 305 306 // vertex and fragment shaders are both be present in a single file, so 307 // scan for the proper header to be the start point, and stamp a 0 in after the end 308 char * start = strstr( (char *)fileBuffer, startToken ); 309 if ( start == NULL ) { 310 common->Printf( ": %s not found\n", startToken ); 311 fileSystem->FreeFile( fileBuffer ); 312 return INVALID_PROGID; 313 } 314 char * end = strstr( start, "END" ); 315 if ( end == NULL ) { 316 common->Printf( ": END not found for %s\n", startToken ); 317 fileSystem->FreeFile( fileBuffer ); 318 return INVALID_PROGID; 319 } 320 end[3] = 0; 321 322 idStr program = start; 323 program.Replace( "vertex.normal", "vertex.attrib[11]" ); 324 program.Replace( "vertex.texcoord[0]", "vertex.attrib[8]" ); 325 program.Replace( "vertex.texcoord", "vertex.attrib[8]" ); 326 327 GLuint progId; 328 qglGenProgramsARB( 1, &progId ); 329 330 qglBindProgramARB( target, progId ); 331 qglGetError(); 332 333 qglProgramStringARB( target, GL_PROGRAM_FORMAT_ASCII_ARB, program.Length(), program.c_str() ); 334 GLenum err = qglGetError(); 335 336 GLint ofs = -1; 337 qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &ofs ); 338 if ( ( err == GL_INVALID_OPERATION ) || ( ofs != -1 ) ) { 339 if ( err == GL_INVALID_OPERATION ) { 340 const GLubyte * str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB ); 341 common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str ); 342 } else { 343 common->Printf( "\nUNKNOWN ERROR\n" ); 344 } 345 if ( ofs < 0 ) { 346 common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0\n" ); 347 } else if ( ofs >= program.Length() ) { 348 common->Printf( "error at end of shader\n" ); 349 } else { 350 common->Printf( "error at %i:\n%s", ofs, program.c_str() + ofs ); 351 } 352 qglDeleteProgramsARB( 1, &progId ); 353 fileSystem->FreeFile( fileBuffer ); 354 return INVALID_PROGID; 355 } 356 common->Printf( "\n" ); 357 fileSystem->FreeFile( fileBuffer ); 358 return progId; 359 } 360 361 /* 362 ================================================================================================ 363 idRenderProgManager::BindShader 364 ================================================================================================ 365 */ 366 void idRenderProgManager::BindShader( int vIndex, int fIndex ) { 367 if ( currentVertexShader == vIndex && currentFragmentShader == fIndex ) { 368 return; 369 } 370 currentVertexShader = vIndex; 371 currentFragmentShader = fIndex; 372 // vIndex denotes the GLSL program 373 if ( vIndex >= 0 && vIndex < glslPrograms.Num() ) { 374 currentRenderProgram = vIndex; 375 RENDERLOG_PRINTF( "Binding GLSL Program %s\n", glslPrograms[vIndex].name.c_str() ); 376 qglUseProgram( glslPrograms[vIndex].progId ); 377 } 378 } 379 380 /* 381 ================================================================================================ 382 idRenderProgManager::Unbind 383 ================================================================================================ 384 */ 385 void idRenderProgManager::Unbind() { 386 currentVertexShader = -1; 387 currentFragmentShader = -1; 388 389 qglUseProgram( 0 ); 390 } 391 392 /* 393 ================================================================================================ 394 idRenderProgManager::SetRenderParms 395 ================================================================================================ 396 */ 397 void idRenderProgManager::SetRenderParms( renderParm_t rp, const float * value, int num ) { 398 for ( int i = 0; i < num; i++ ) { 399 SetRenderParm( (renderParm_t)(rp + i), value + ( i * 4 ) ); 400 } 401 } 402 403 /* 404 ================================================================================================ 405 idRenderProgManager::SetRenderParm 406 ================================================================================================ 407 */ 408 void idRenderProgManager::SetRenderParm( renderParm_t rp, const float * value ) { 409 SetUniformValue( rp, value ); 410 } 411