/* ================= R_LinkGLSLShader links the GLSL vertex and fragment shaders together to form a GLSL program ================= */ bool R_LinkGLSLShader( shaderProgram_t *shaderProgram, bool needsAttributes ) { GLint linked; shaderProgram->program = qglCreateProgramObjectARB( ); qglAttachObjectARB( shaderProgram->program, shaderProgram->vertexShader ); qglAttachObjectARB( shaderProgram->program, shaderProgram->fragmentShader ); if ( needsAttributes ) { qglBindAttribLocationARB( shaderProgram->program, 8, "attr_TexCoord" ); qglBindAttribLocationARB( shaderProgram->program, 9, "attr_Tangent" ); qglBindAttribLocationARB( shaderProgram->program, 10, "attr_Bitangent" ); qglBindAttribLocationARB( shaderProgram->program, 11, "attr_Normal" ); } qglLinkProgramARB( shaderProgram->program ); qglGetObjectParameterivARB( shaderProgram->program, GL_OBJECT_LINK_STATUS_ARB, &linked ); if ( !linked ) { common->Printf( "R_LinkGLSLShader: program failed to link\n" ); return false; } return true; }
static void printGlslLog( GLhandleARB obj ) { int infoLogLength = 0; char infoLog[1024]; int len; qglGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infoLogLength); if (infoLogLength > 0) { qglGetInfoLogARB(obj, 1024, &len, infoLog); Com_VPrintf( "%s\n", infoLog ); } }
static GLhandleARB R_CompileGLSLShader( GLhandleARB programObject, GLenum shaderType, unsigned int sourceStringCount, const char *sourceStrings[] ) { GLhandleARB shaderObject; GLint shaderCompiled; const char *shaderName; int i; char compileLog[ 4096 ]; if( shaderType == GL_VERTEX_SHADER_ARB ) { shaderName = "vertex shader"; } else { shaderName = "fragment shader"; } // run a basic error check for (i = 0 ; i < sourceStringCount ; i++) { if (sourceStrings[i] == 0) { Con_Printf("R_CompileGLSLShader: string #%i of %s is NULL!\n", i, shaderName); return 0; } } // R_CheckError(); shaderObject = qglCreateShaderObjectARB( shaderType ); if( shaderObject == 0 ) { // R_CheckError(); return 0; } if( sourceStringCount != 0 ) { qglShaderSourceARB( shaderObject, sourceStringCount, sourceStrings, NULL); qglCompileShaderARB( shaderObject ); // R_CheckError(); qglGetObjectParameterivARB( shaderObject, GL_OBJECT_COMPILE_STATUS_ARB, &shaderCompiled ); qglGetInfoLogARB( shaderObject, sizeof(compileLog), NULL, compileLog); if( *compileLog ) { Con_Printf("%s compile log:\n%s\n", shaderName, compileLog); } if( !shaderCompiled ) { qglDeleteObjectARB( shaderObject ); // R_CheckError(); return 0; } } // TODO: check whether an empty shader object can be compiled! qglAttachObjectARB( programObject, shaderObject); qglDeleteObjectARB( shaderObject ); //R_CheckError(); return shaderObject; }
/* ================= R_ValidateGLSLProgram makes sure GLSL program is valid ================= */ bool R_ValidateGLSLProgram( shaderProgram_t *shaderProgram ) { GLint validProgram; qglValidateProgramARB( shaderProgram->program ); qglGetObjectParameterivARB( shaderProgram->program, GL_OBJECT_VALIDATE_STATUS_ARB, &validProgram ); if( !validProgram ) { common->Printf( "R_ValidateGLSLProgram: program invalid\n" ); return false; } return true; }
static void GLSL_ValidateProgram(GLhandleARB program) { GLint validated; qglValidateProgramARB(program); qglGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated); if(!validated) { GLSL_PrintInfoLog(program, qfalse); ri.Printf(PRINT_ALL, "\n"); ri.Error(ERR_DROP, "shaders failed to validate"); } }
static void GLSL_LinkProgram(GLhandleARB program) { GLint linked; qglLinkProgramARB(program); qglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked); if(!linked) { GLSL_PrintInfoLog(program, qfalse); ri.Printf(PRINT_ALL, "\n"); ri.Error(ERR_DROP, "shaders failed to link"); } }
static unsigned int R_CompileGLSLProgram(unsigned int vertexstrings_count, const char **vertexstrings_list, unsigned int fragmentstrings_count, const char **fragmentstrings_list) { GLint programLinked; GLhandleARB programObject = 0; char compileLog[4096]; //R_CheckError(); // if (!R.ext.ARB_fragment_shader) if (!gl_support_GLSL_shaders) return 0; programObject = qglCreateProgramObjectARB(); //R_CheckError(); if( programObject == 0 ) { return 0; } if( R_CompileGLSLShader( programObject, GL_VERTEX_SHADER_ARB, vertexstrings_count, vertexstrings_list ) == 0 || R_CompileGLSLShader( programObject, GL_FRAGMENT_SHADER_ARB, fragmentstrings_count, fragmentstrings_list ) == 0 ) { qglDeleteObjectARB( programObject ); // R_CheckError(); return 0; } qglLinkProgramARB( programObject ); // R_CheckError(); qglGetObjectParameterivARB( programObject, GL_OBJECT_LINK_STATUS_ARB, &programLinked ); qglGetInfoLogARB( programObject, sizeof( compileLog ), NULL, compileLog ); if( *compileLog ) { Con_Printf("program link log:\n%s\n", compileLog); // software vertex shader is ok but software fragment shader is WAY // too slow, fail program if so. // NOTE: this string might be ATI specific, but that's ok because the // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a // software fragment shader due to low instruction and dependent // texture limits. if (strstr( compileLog, "fragment shader will run in software" )) programLinked = false; } //R_CheckError(); if( !programLinked ) { qglDeleteObjectARB( programObject ); return 0; } //R_CheckError(); return (unsigned int) programObject; }
static void GLSL_ShowProgramUniforms(GLhandleARB program) { int i, count, size; GLenum type; char uniformName[1000]; // query the number of active uniforms qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); // Loop over each of the active uniforms, and set their value for(i = 0; i < count; i++) { qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); } }
static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) { char *msg; static char msgPart[1024]; int maxLength = 0; int i; int printLevel = developerOnly ? PRINT_DEVELOPER : PRINT_ALL; qglGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); if (maxLength <= 0) { ri.Printf(printLevel, "No compile log.\n"); return; } ri.Printf(printLevel, "compile log:\n"); if (maxLength < 1023) { qglGetInfoLogARB(object, maxLength, &maxLength, msgPart); msgPart[maxLength + 1] = '\0'; ri.Printf(printLevel, "%s\n", msgPart); } else { msg = ri.Malloc(maxLength); qglGetInfoLogARB(object, maxLength, &maxLength, msg); for(i = 0; i < maxLength; i += 1024) { Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); ri.Printf(printLevel, "%s\n", msgPart); } ri.Free(msg); } }
qboolean R_Shader_StartLightPass( unsigned int lightIndex ) { GLint valid; R_ShaderLight *light = GetLightFromIndex( lightIndex ); matrix4x4_t *worldToViewMatrix = &r_refdef.lightShader.worldToViewMatrix; vec3_t lightPosition, newcolor; float f; assert( light->active == true ); // setup cubemap texture generation if( gl_support_cubemaps ) { matrix4x4_t worldToLightMatrix; matrix4x4_t viewToWorldMatrix; matrix4x4_t viewToLightMatrix; // setup the cubemap qglSelectTextureARB( GL_TEXTURE1_ARB ); glEnable( GL_TEXTURE_CUBE_MAP_ARB ); glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, GL_LoadCubeTexImage( light->cubemapname, false, true ) ); qglSelectTextureARB( GL_TEXTURE0_ARB ); // invert worldToViewMatrix worldToLightMatrix = GetWorldToLightMatrix( light ); Matrix4x4_Invert_Simple( &viewToWorldMatrix, worldToViewMatrix ); Matrix4x4_Concat( &viewToLightMatrix, &worldToLightMatrix, &viewToWorldMatrix ); qglUniformMatrix4fvARB( r_refdef.lightShader.viewToLightMatrix, 1, true, (float *)&viewToLightMatrix.m ); } Matrix4x4_Transform( worldToViewMatrix, light->origin, lightPosition ); //Con_Printf( "Light distance to origin: %f (vs %f)\n", VectorDistance( light->origin, r_refdef.vieworg ), VectorLength( lightPosition ) ); qglUniform3fvARB( r_refdef.lightShader.lightPosition, 1, lightPosition ); f = (light->style >= 0 ? d_lightstylevalue[light->style] : 128) * (1.0f / 256.0f) * r_shadow_lightintensityscale.value; VectorScale(light->color, f, newcolor); qglUniform3fvARB( r_refdef.lightShader.lightColor, 1, newcolor ); qglUniform1fARB( r_refdef.lightShader.lightMaxDistance, light->maxDistance ); qglValidateProgramARB( r_refdef.lightShader.programObject ); qglGetObjectParameterivARB( r_refdef.lightShader.programObject, GL_OBJECT_VALIDATE_STATUS_ARB, &valid ); return valid == true; }
static void GLSL_PrintShaderSource(GLhandleARB object) { char *msg; static char msgPart[1024]; int maxLength = 0; int i; qglGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength); msg = ri.Malloc(maxLength); qglGetShaderSourceARB(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); } ri.Free(msg); }
static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, const GLcharARB *buffer, int size, GLenum shaderType) { GLint compiled; GLhandleARB shader; shader = qglCreateShaderObjectARB(shaderType); qglShaderSourceARB(shader, 1, (const GLcharARB **)&buffer, &size); // compile shader qglCompileShaderARB(shader); // check if shader compiled qglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); if(!compiled) { GLSL_PrintShaderSource(shader); GLSL_PrintInfoLog(shader, qfalse); ri.Error(ERR_DROP, "Couldn't compile shader"); return 0; } //GLSL_PrintInfoLog(shader, qtrue); //GLSL_PrintShaderSource(shader); if (*prevShader) { qglDetachObjectARB(program, *prevShader); qglDeleteObjectARB(*prevShader); } // attach shader to program qglAttachObjectARB(program, shader); *prevShader = shader; return 1; }
static 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. qglUseProgramObjectARB(program); // check for GL Errors // query the number of active uniforms qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); // Loop over each of the active uniforms, and set their value for(i = 0; i < count; i++) { qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); } qglUseProgramObjectARB(0); }