DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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