static void R_ShutdownShader (r_shader_t* sh) { qglDeleteShader(sh->id); OBJZERO(*sh); }
/** * @brief Reads/Preprocesses/Compiles the specified shader into a program. * @param[in] type The type of shader, currently either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. * @param[in] name The file name of the shader to load from ./base/shaders/ (e.g. "world_fs.glsl"). * @return A structure used as a handle to the compiled shader (program). */ static r_shader_t* R_LoadShader (const GLenum type, const char* name) { r_shader_t* sh; char path[MAX_QPATH], *src[1]; unsigned e, length[1]; char* srcBuf; byte* buf; int i; size_t bufLength = SHADER_BUF_SIZE; size_t initializeLength; #ifdef DEBUG /* Used to contain result of shader compile.*/ char log[MAX_STRING_CHARS]; #endif snprintf(path, sizeof(path), "shaders/%s", name); if (FS_LoadFile(path, &buf) == -1) { Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Failed to load ./base/shaders/%s.\n", name); return nullptr; } Com_DPrintf(DEBUG_RENDERER, "R_LoadShader: Loading ./base/shaders/%s.\n", name); char* const source = srcBuf = Mem_PoolAllocTypeN(char, bufLength, vid_imagePool); initializeLength = R_InitializeShader(type, name, srcBuf, bufLength); srcBuf += initializeLength; bufLength -= initializeLength; R_PreprocessShader(name, (const char*)buf, srcBuf, &bufLength); FS_FreeFile(buf); src[0] = source; length[0] = strlen(source); for (i = 0; i < MAX_SHADERS; i++) { sh = &r_state.shaders[i]; if (!sh->id) break; } if (i == MAX_SHADERS) { Com_Printf("R_LoadShader: MAX_SHADERS reached.\n"); Mem_Free(source); return nullptr; } Q_strncpyz(sh->name, name, sizeof(sh->name)); sh->type = type; sh->id = qglCreateShader(sh->type); if (!sh->id) { Mem_Free(source); return nullptr; } /* upload the shader source */ qglShaderSource(sh->id, 1, src, length); /* compile it and check for errors */ qglCompileShader(sh->id); Mem_Free(source); qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e); #ifdef DEBUG qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log); Com_Printf("R_LoadShader: %s: %s", sh->name, log); #endif if (!e) { #ifndef DEBUG char log[MAX_STRING_CHARS]; qglGetShaderInfoLog(sh->id, sizeof(log) - 1, nullptr, log); Com_Printf("R_LoadShader: %s: %s", sh->name, log); #endif qglDeleteShader(sh->id); OBJZERO(*sh); return nullptr; } return sh; }
/* ================================================================================================ idRenderProgManager::LoadGLSLShader ================================================================================================ */ GLuint idRenderProgManager::LoadGLSLShader( GLenum target, const char * name, idList<int> & uniforms ) { idStr inFile; idStr outFileHLSL; idStr outFileGLSL; idStr outFileUniforms; inFile.Format( "renderprogs\\%s", name ); inFile.StripFileExtension(); outFileHLSL.Format( "renderprogs\\glsl\\%s", name ); outFileHLSL.StripFileExtension(); outFileGLSL.Format( "renderprogs\\glsl\\%s", name ); outFileGLSL.StripFileExtension(); outFileUniforms.Format( "renderprogs\\glsl\\%s", name ); outFileUniforms.StripFileExtension(); if ( target == GL_FRAGMENT_SHADER ) { inFile += ".pixel"; outFileHLSL += "_fragment.hlsl"; outFileGLSL += "_fragment.glsl"; outFileUniforms += "_fragment.uniforms"; } else { inFile += ".vertex"; outFileHLSL += "_vertex.hlsl"; outFileGLSL += "_vertex.glsl"; outFileUniforms += "_vertex.uniforms"; } // first check whether we already have a valid GLSL file and compare it to the hlsl timestamp; ID_TIME_T hlslTimeStamp; int hlslFileLength = fileSystem->ReadFile( inFile.c_str(), NULL, &hlslTimeStamp ); ID_TIME_T glslTimeStamp; int glslFileLength = fileSystem->ReadFile( outFileGLSL.c_str(), NULL, &glslTimeStamp ); // if the glsl file doesn't exist or we have a newer HLSL file we need to recreate the glsl file. idStr programGLSL; idStr programUniforms; if ( ( glslFileLength <= 0 ) || ( hlslTimeStamp > glslTimeStamp ) ) { if ( hlslFileLength <= 0 ) { // hlsl file doesn't even exist bail out return false; } void * hlslFileBuffer = NULL; int len = fileSystem->ReadFile( inFile.c_str(), &hlslFileBuffer ); if ( len <= 0 ) { return false; } idStr hlslCode( ( const char* ) hlslFileBuffer ); idStr programHLSL = StripDeadCode( hlslCode, inFile ); programGLSL = ConvertCG2GLSL( programHLSL, inFile, target == GL_VERTEX_SHADER, programUniforms ); fileSystem->WriteFile( outFileHLSL, programHLSL.c_str(), programHLSL.Length(), "fs_basepath" ); fileSystem->WriteFile( outFileGLSL, programGLSL.c_str(), programGLSL.Length(), "fs_basepath" ); if ( r_useUniformArrays.GetBool() ) { fileSystem->WriteFile( outFileUniforms, programUniforms.c_str(), programUniforms.Length(), "fs_basepath" ); } } else { // read in the glsl file void * fileBufferGLSL = NULL; int lengthGLSL = fileSystem->ReadFile( outFileGLSL.c_str(), &fileBufferGLSL ); if ( lengthGLSL <= 0 ) { idLib::Error( "GLSL file %s could not be loaded and may be corrupt", outFileGLSL.c_str() ); } programGLSL = ( const char * ) fileBufferGLSL; Mem_Free( fileBufferGLSL ); if ( r_useUniformArrays.GetBool() ) { // read in the uniform file void * fileBufferUniforms = NULL; int lengthUniforms = fileSystem->ReadFile( outFileUniforms.c_str(), &fileBufferUniforms ); if ( lengthUniforms <= 0 ) { idLib::Error( "uniform file %s could not be loaded and may be corrupt", outFileUniforms.c_str() ); } programUniforms = ( const char* ) fileBufferUniforms; Mem_Free( fileBufferUniforms ); } } // find the uniforms locations in either the vertex or fragment uniform array if ( r_useUniformArrays.GetBool() ) { uniforms.Clear(); idLexer src( programUniforms, programUniforms.Length(), "uniforms" ); idToken token; while ( src.ReadToken( &token ) ) { int index = -1; for ( int i = 0; i < RENDERPARM_TOTAL && index == -1; i++ ) { const char * parmName = GetGLSLParmName( i ); if ( token == parmName ) { index = i; } } for ( int i = 0; i < MAX_GLSL_USER_PARMS && index == -1; i++ ) { const char * parmName = GetGLSLParmName( RENDERPARM_USER + i ); if ( token == parmName ) { index = RENDERPARM_USER + i; } } if ( index == -1 ) { idLib::Error( "couldn't find uniform %s for %s", token.c_str(), outFileGLSL.c_str() ); } uniforms.Append( index ); } } // create and compile the shader const GLuint shader = qglCreateShader( target ); if ( shader ) { const char * source[1] = { programGLSL.c_str() }; qglShaderSource( shader, 1, source, NULL ); qglCompileShader( shader ); int infologLength = 0; qglGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infologLength ); if ( infologLength > 1 ) { idTempArray<char> infoLog( infologLength ); int charsWritten = 0; qglGetShaderInfoLog( shader, infologLength, &charsWritten, infoLog.Ptr() ); // catch the strings the ATI and Intel drivers output on success if ( strstr( infoLog.Ptr(), "successfully compiled to run on hardware" ) != NULL || strstr( infoLog.Ptr(), "No errors." ) != NULL ) { //idLib::Printf( "%s program %s from %s compiled to run on hardware\n", typeName, GetName(), GetFileName() ); } else if ( r_displayGLSLCompilerMessages.GetBool() ) { idLib::Printf( "While compiling %s program %s\n", ( target == GL_FRAGMENT_SHADER ) ? "fragment" : "vertex" , inFile.c_str() ); const char separator = '\n'; idList<idStr> lines; lines.Clear(); idStr source( programGLSL ); lines.Append( source ); for ( int index = 0, ofs = lines[index].Find( separator ); ofs != -1; index++, ofs = lines[index].Find( separator ) ) { lines.Append( lines[index].c_str() + ofs + 1 ); lines[index].CapLength( ofs ); } idLib::Printf( "-----------------\n" ); for ( int i = 0; i < lines.Num(); i++ ) { idLib::Printf( "%3d: %s\n", i+1, lines[i].c_str() ); } idLib::Printf( "-----------------\n" ); idLib::Printf( "%s\n", infoLog.Ptr() ); } } GLint compiled = GL_FALSE; qglGetShaderiv( shader, GL_COMPILE_STATUS, &compiled ); if ( compiled == GL_FALSE ) { qglDeleteShader( shader ); return INVALID_PROGID; } } return shader; }
static bool RB_GLSL_InitShaders( ) { // load interation shaders R_LoadGLSLShader( "interaction.vertex", &interactionShader, GL_VERTEX_SHADER_ARB ); R_LoadGLSLShader( "interaction.fragment", &interactionShader, GL_FRAGMENT_SHADER_ARB ); if ( interactionShader.fragmentShader == -1 || interactionShader.vertexShader == -1 || !R_LinkGLSLShader( &interactionShader, true ) && !R_ValidateGLSLProgram( &interactionShader ) ) { if (interactionShader.fragmentShader != -1) qglDeleteShader(interactionShader.fragmentShader); if (interactionShader.vertexShader != -1) qglDeleteShader(interactionShader.vertexShader); interactionShader.fragmentShader = -1; interactionShader.vertexShader = -1; common->Printf( "GLSL interactionShader failed to init.\n" ); return false; } else { // set uniform locations interactionShader.u_normalTexture = qglGetUniformLocationARB( interactionShader.program, "u_normalTexture" ); interactionShader.u_lightFalloffTexture = qglGetUniformLocationARB( interactionShader.program, "u_lightFalloffTexture" ); interactionShader.u_lightProjectionTexture = qglGetUniformLocationARB( interactionShader.program, "u_lightProjectionTexture" ); interactionShader.u_diffuseTexture = qglGetUniformLocationARB( interactionShader.program, "u_diffuseTexture" ); interactionShader.u_specularTexture = qglGetUniformLocationARB( interactionShader.program, "u_specularTexture" ); interactionShader.modelMatrix = qglGetUniformLocationARB( interactionShader.program, "u_modelMatrix" ); interactionShader.localLightOrigin = qglGetUniformLocationARB( interactionShader.program, "u_lightOrigin" ); interactionShader.localViewOrigin = qglGetUniformLocationARB( interactionShader.program, "u_viewOrigin" ); interactionShader.lightProjectionS = qglGetUniformLocationARB( interactionShader.program, "u_lightProjectionS" ); interactionShader.lightProjectionT = qglGetUniformLocationARB( interactionShader.program, "u_lightProjectionT" ); interactionShader.lightProjectionQ = qglGetUniformLocationARB( interactionShader.program, "u_lightProjectionQ" ); interactionShader.lightFalloff = qglGetUniformLocationARB( interactionShader.program, "u_lightFalloff" ); interactionShader.bumpMatrixS = qglGetUniformLocationARB( interactionShader.program, "u_bumpMatrixS" ); interactionShader.bumpMatrixT = qglGetUniformLocationARB( interactionShader.program, "u_bumpMatrixT" ); interactionShader.diffuseMatrixS = qglGetUniformLocationARB( interactionShader.program, "u_diffuseMatrixS" ); interactionShader.diffuseMatrixT = qglGetUniformLocationARB( interactionShader.program, "u_diffuseMatrixT" ); interactionShader.specularMatrixS = qglGetUniformLocationARB( interactionShader.program, "u_specularMatrixS" ); interactionShader.specularMatrixT = qglGetUniformLocationARB( interactionShader.program, "u_specularMatrixT" ); interactionShader.colorModulate = qglGetUniformLocationARB( interactionShader.program, "u_colorModulate" ); interactionShader.colorAdd = qglGetUniformLocationARB( interactionShader.program, "u_colorAdd" ); interactionShader.diffuseColor = qglGetUniformLocationARB( interactionShader.program, "u_diffuseColor" ); interactionShader.specularColor = qglGetUniformLocationARB( interactionShader.program, "u_specularColor" ); // set texture locations qglUseProgramObjectARB( interactionShader.program ); qglUniform1iARB( interactionShader.u_normalTexture, 0 ); qglUniform1iARB( interactionShader.u_lightFalloffTexture, 1 ); qglUniform1iARB( interactionShader.u_lightProjectionTexture, 2 ); qglUniform1iARB( interactionShader.u_diffuseTexture, 3 ); qglUniform1iARB( interactionShader.u_specularTexture, 4 ); qglUseProgramObjectARB( 0 ); } // load ambient interation shaders R_LoadGLSLShader( "ambientInteraction.vertex", &ambientInteractionShader, GL_VERTEX_SHADER_ARB ); R_LoadGLSLShader( "ambientInteraction.fragment", &ambientInteractionShader, GL_FRAGMENT_SHADER_ARB ); if ( ambientInteractionShader.fragmentShader == -1 || ambientInteractionShader.vertexShader == -1 || !R_LinkGLSLShader( &ambientInteractionShader, true ) && !R_ValidateGLSLProgram( &ambientInteractionShader ) ) { if (ambientInteractionShader.fragmentShader != -1) qglDeleteShader(ambientInteractionShader.fragmentShader); if (ambientInteractionShader.vertexShader != -1) qglDeleteShader(ambientInteractionShader.vertexShader); ambientInteractionShader.fragmentShader = -1; ambientInteractionShader.vertexShader = -1; common->Printf( "GLSL ambientInteractionShader failed to init.\n" ); return false; } else { // set uniform locations ambientInteractionShader.u_normalTexture = qglGetUniformLocationARB( ambientInteractionShader.program, "u_normalTexture" ); ambientInteractionShader.u_lightFalloffTexture = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightFalloffTexture" ); ambientInteractionShader.u_lightProjectionTexture = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightProjectionTexture" ); ambientInteractionShader.u_diffuseTexture = qglGetUniformLocationARB( ambientInteractionShader.program, "u_diffuseTexture" ); ambientInteractionShader.modelMatrix = qglGetUniformLocationARB( ambientInteractionShader.program, "u_modelMatrix" ); ambientInteractionShader.localLightOrigin = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightOrigin" ); ambientInteractionShader.lightProjectionS = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightProjectionS" ); ambientInteractionShader.lightProjectionT = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightProjectionT" ); ambientInteractionShader.lightProjectionQ = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightProjectionQ" ); ambientInteractionShader.lightFalloff = qglGetUniformLocationARB( ambientInteractionShader.program, "u_lightFalloff" ); ambientInteractionShader.bumpMatrixS = qglGetUniformLocationARB( ambientInteractionShader.program, "u_bumpMatrixS" ); ambientInteractionShader.bumpMatrixT = qglGetUniformLocationARB( ambientInteractionShader.program, "u_bumpMatrixT" ); ambientInteractionShader.diffuseMatrixS = qglGetUniformLocationARB( ambientInteractionShader.program, "u_diffuseMatrixS" ); ambientInteractionShader.diffuseMatrixT = qglGetUniformLocationARB( ambientInteractionShader.program, "u_diffuseMatrixT" ); ambientInteractionShader.colorModulate = qglGetUniformLocationARB( ambientInteractionShader.program, "u_colorModulate" ); ambientInteractionShader.colorAdd = qglGetUniformLocationARB( ambientInteractionShader.program, "u_colorAdd" ); ambientInteractionShader.diffuseColor = qglGetUniformLocationARB( ambientInteractionShader.program, "u_diffuseColor" ); // set texture locations qglUseProgramObjectARB( ambientInteractionShader.program ); qglUniform1iARB( ambientInteractionShader.u_normalTexture, 0 ); qglUniform1iARB( ambientInteractionShader.u_lightFalloffTexture, 1 ); qglUniform1iARB( ambientInteractionShader.u_lightProjectionTexture, 2 ); qglUniform1iARB( ambientInteractionShader.u_diffuseTexture, 3 ); qglUseProgramObjectARB( 0 ); } // load stencil shadow extrusion shaders R_LoadGLSLShader( "stencilshadow.vertex", &stencilShadowShader, GL_VERTEX_SHADER_ARB ); R_LoadGLSLShader( "stencilshadow.fragment", &stencilShadowShader, GL_FRAGMENT_SHADER_ARB ); if ( stencilShadowShader.fragmentShader == -1 || stencilShadowShader.vertexShader == -1 || !R_LinkGLSLShader( &stencilShadowShader, false ) && !R_ValidateGLSLProgram( &stencilShadowShader ) ) { if (stencilShadowShader.fragmentShader != -1) qglDeleteShader(stencilShadowShader.fragmentShader); if (stencilShadowShader.vertexShader != -1) qglDeleteShader(stencilShadowShader.vertexShader); stencilShadowShader.fragmentShader = -1; stencilShadowShader.vertexShader = -1; common->Printf( "GLSL stencilShadowShader failed to init.\n" ); return false; } else { // set uniform locations stencilShadowShader.localLightOrigin = qglGetUniformLocationARB( stencilShadowShader.program, "u_lightOrigin" ); } return true; }
/* ================= R_LoadGLSLShader loads GLSL vertex or fragment shaders ================= */ bool R_LoadGLSLShader( const char *name, shaderProgram_t *shaderProgram, GLenum type ) { idStr fullPath = "gl2progs/"; fullPath += name; char *fileBuffer; char *buffer; common->Printf( "%s", fullPath.c_str() ); // load the program even if we don't support it, so // fs_copyfiles can generate cross-platform data dumps fileSystem->ReadFile( fullPath.c_str(), (void **)&fileBuffer, NULL ); if ( !fileBuffer ) { common->Printf( ": File not found\n" ); return false; } // copy to stack memory and free buffer = (char *)_alloca( strlen( fileBuffer ) + 1 ); strcpy( buffer, fileBuffer ); fileSystem->FreeFile( fileBuffer ); if ( !glConfig.isInitialized ) { return false; } GLuint shader; switch( type ) { case GL_VERTEX_SHADER_ARB: if (shaderProgram->vertexShader != -1) qglDeleteShader(shaderProgram->vertexShader); shaderProgram->vertexShader = -1; // create vertex shader shader = qglCreateShaderObjectARB( GL_VERTEX_SHADER_ARB ); qglShaderSourceARB( shader, 1, (const GLcharARB **)&buffer, 0 ); qglCompileShaderARB( shader ); break; case GL_FRAGMENT_SHADER_ARB: if (shaderProgram->fragmentShader != -1) qglDeleteShader(shaderProgram->fragmentShader); shaderProgram->fragmentShader = -1; // create fragment shader shader = qglCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB ); qglShaderSourceARB( shader, 1, (const GLcharARB **)&buffer, 0 ); qglCompileShaderARB( shader ); break; default: common->Printf( "R_LoadGLSLShader: no type\n" ); return false; } GLint logLength; qglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 1) { GLchar *log = (GLchar *)malloc(logLength); qglGetShaderInfoLog(shader, logLength, &logLength, log); common->Printf((const char*)log); free(log); } GLint status; qglGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status == 0) { qglDeleteShader(shader); return false; } switch( type ) { case GL_VERTEX_SHADER_ARB: shaderProgram->vertexShader = shader; break; case GL_FRAGMENT_SHADER_ARB: shaderProgram->fragmentShader = shader; break; } common->Printf( "\n" ); return true; }
/* * @brief */ static r_shader_t *R_LoadShader(GLenum type, const char *name) { r_shader_t *sh; char path[MAX_QPATH], *src[1], log[MAX_STRING_CHARS]; uint32_t e, length[1]; void *buf; int32_t i, len; g_snprintf(path, sizeof(path), "shaders/%s", name); if ((len = Fs_Load(path, &buf)) == -1) { Com_Warn("Failed to load %s\n", name); return NULL; } src[0] = (char *) buf; length[0] = len; for (i = 0; i < MAX_SHADERS; i++) { sh = &r_state.shaders[i]; if (!sh->id) break; } if (i == MAX_SHADERS) { Com_Warn("MAX_SHADERS reached\n"); Fs_Free(buf); return NULL; } g_strlcpy(sh->name, name, sizeof(sh->name)); sh->type = type; sh->id = qglCreateShader(sh->type); if (!sh->id) { Fs_Free(buf); return NULL; } // upload the shader source qglShaderSource(sh->id, 1, src, length); // compile it and check for errors qglCompileShader(sh->id); qglGetShaderiv(sh->id, GL_COMPILE_STATUS, &e); if (!e) { qglGetShaderInfoLog(sh->id, sizeof(log) - 1, NULL, log); Com_Warn("%s: %s\n", sh->name, log); qglDeleteShader(sh->id); memset(sh, 0, sizeof(*sh)); Fs_Free(buf); return NULL; } Fs_Free(buf); return sh; }
/* * @brief */ static void R_ShutdownShader(r_shader_t *sh) { qglDeleteShader(sh->id); memset(sh, 0, sizeof(r_shader_t)); }