/* * @brief */ void R_ProgramVariable(r_variable_t *variable, GLenum type, const char *name) { memset(variable, 0, sizeof(*variable)); variable->location = -1; if (!r_state.active_program) { Com_Warn("No program currently bound\n"); return; } switch (type) { case R_ATTRIBUTE: variable->location = qglGetAttribLocation(r_state.active_program->id, name); break; default: variable->location = qglGetUniformLocation(r_state.active_program->id, name); break; } if (variable->location == -1) { Com_Warn("Failed to resolve variable %s in program %s\n", name, r_state.active_program->name); return; } variable->type = type; g_strlcpy(variable->name, name, sizeof(variable->name)); memset(&variable->value, 0xff, sizeof(variable->value)); }
static r_progvar_t* R_ProgramVariable (int type, const char* name) { r_progvar_t* v; int i; if (!r_state.active_program) { Com_DPrintf(DEBUG_RENDERER, "R_ProgramVariable: \"%s\" - No program bound.\n", name); return nullptr; } /* find the variable */ for (i = 0; i < MAX_PROGRAM_VARS; i++) { v = &r_state.active_program->vars[i]; if (!v->location) break; if (v->type == type && Q_streq(v->name, name)) return v; } if (i == MAX_PROGRAM_VARS) { Com_Printf("R_ProgramVariable: MAX_PROGRAM_VARS reached.\n"); return nullptr; } /* or query for it */ if (type == GL_UNIFORM) v->location = qglGetUniformLocation(r_state.active_program->id, name); else v->location = qglGetAttribLocation(r_state.active_program->id, name); if (v->location == -1) { Com_Printf("R_ProgramVariable: Could not find parameter %s in program %s.\n", name, r_state.active_program->name); v->location = 0; return nullptr; } v->type = type; Q_strncpyz(v->name, name, sizeof(v->name)); return v; }
/* ================================================================================================ idRenderProgManager::LoadGLSLProgram ================================================================================================ */ void idRenderProgManager::LoadGLSLProgram( const int programIndex, const int vertexShaderIndex, const int fragmentShaderIndex ) { glslProgram_t & prog = glslPrograms[programIndex]; if ( prog.progId != INVALID_PROGID ) { return; // Already loaded } GLuint vertexProgID = ( vertexShaderIndex != -1 ) ? vertexShaders[ vertexShaderIndex ].progId : INVALID_PROGID; GLuint fragmentProgID = ( fragmentShaderIndex != -1 ) ? fragmentShaders[ fragmentShaderIndex ].progId : INVALID_PROGID; const GLuint program = qglCreateProgram(); if ( program ) { if ( vertexProgID != INVALID_PROGID ) { qglAttachShader( program, vertexProgID ); } if ( fragmentProgID != INVALID_PROGID ) { qglAttachShader( program, fragmentProgID ); } // bind vertex attribute locations for ( int i = 0; attribsPC[i].glsl != NULL; i++ ) { if ( ( attribsPC[i].flags & AT_VS_IN ) != 0 ) { qglBindAttribLocation( program, attribsPC[i].bind, attribsPC[i].glsl ); } } qglLinkProgram( program ); int infologLength = 0; qglGetProgramiv( program, GL_INFO_LOG_LENGTH, &infologLength ); if ( infologLength > 1 ) { char * infoLog = (char *)malloc( infologLength ); int charsWritten = 0; qglGetProgramInfoLog( program, infologLength, &charsWritten, infoLog ); // catch the strings the ATI and Intel drivers output on success if ( strstr( infoLog, "Vertex shader(s) linked, fragment shader(s) linked." ) != NULL || strstr( infoLog, "No errors." ) != NULL ) { //idLib::Printf( "render prog %s from %s linked\n", GetName(), GetFileName() ); } else { idLib::Printf( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n", programIndex, ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>", ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" ); idLib::Printf( "%s\n", infoLog ); } free( infoLog ); } } int linked = GL_FALSE; qglGetProgramiv( program, GL_LINK_STATUS, &linked ); if ( linked == GL_FALSE ) { qglDeleteProgram( program ); idLib::Error( "While linking GLSL program %d with vertexShader %s and fragmentShader %s\n", programIndex, ( vertexShaderIndex >= 0 ) ? vertexShaders[vertexShaderIndex].name.c_str() : "<Invalid>", ( fragmentShaderIndex >= 0 ) ? fragmentShaders[ fragmentShaderIndex ].name.c_str() : "<Invalid>" ); return; } if ( r_useUniformArrays.GetBool() ) { prog.vertexUniformArray = qglGetUniformLocation( program, VERTEX_UNIFORM_ARRAY_NAME ); prog.fragmentUniformArray = qglGetUniformLocation( program, FRAGMENT_UNIFORM_ARRAY_NAME ); assert( prog.vertexUniformArray != -1 || vertexShaderIndex < 0 || vertexShaders[vertexShaderIndex].uniforms.Num() == 0 ); assert( prog.fragmentUniformArray != -1 || fragmentShaderIndex < 0 || fragmentShaders[fragmentShaderIndex].uniforms.Num() == 0 ); } else { // store the uniform locations after we have linked the GLSL program prog.uniformLocations.Clear(); for ( int i = 0; i < RENDERPARM_TOTAL; i++ ) { const char * parmName = GetGLSLParmName( i ); GLint loc = qglGetUniformLocation( program, parmName ); if ( loc != -1 ) { glslUniformLocation_t uniformLocation; uniformLocation.parmIndex = i; uniformLocation.uniformIndex = loc; prog.uniformLocations.Append( uniformLocation ); } } // store the USER uniform locations for ( int i = 0; i < MAX_GLSL_USER_PARMS; i++ ) { const char * parmName = GetGLSLParmName( RENDERPARM_USER + i ); GLint loc = qglGetUniformLocation( program, parmName ); if ( loc != -1 ) { glslUniformLocation_t uniformLocation; uniformLocation.parmIndex = RENDERPARM_USER + i; uniformLocation.uniformIndex = loc; prog.uniformLocations.Append( uniformLocation ); } } // sort the uniforms based on index prog.uniformLocations.SortWithTemplate( idSort_QuickUniforms() ); } // get the uniform buffer binding for skinning joint matrices GLint blockIndex = qglGetUniformBlockIndex( program, "matrices_ubo" ); if ( blockIndex != -1 ) { qglUniformBlockBinding( program, blockIndex, 0 ); } // set the texture unit locations once for the render program. We only need to do this once since we only link the program once qglUseProgram( program ); for ( int i = 0; i < MAX_PROG_TEXTURE_PARMS; ++i ) { GLint loc = qglGetUniformLocation( program, va( "samp%d", i ) ); if ( loc != -1 ) { qglUniform1i( loc, i ); } } idStr programName = vertexShaders[ vertexShaderIndex ].name; programName.StripFileExtension(); prog.name = programName; prog.progId = program; prog.fragmentShaderIndex = fragmentShaderIndex; prog.vertexShaderIndex = vertexShaderIndex; }
//Does a water warp on the pre-fragmented glpoly_t chain void EmitWaterPolys (msurface_t *fa) { glpoly_t *p; float *v, s, t, os, ot; int i; byte *col; extern cvar_t r_telecolor, r_watercolor, r_slimecolor, r_lavacolor; float wateralpha = bound((1 - r_refdef2.max_watervis), r_wateralpha.value, 1); vec3_t nv; GLint shader, u_gamma, u_contrast; GL_DisableMultitexture(); if (gl_fogenable.value) glEnable(GL_FOG); GL_Bind (fa->texinfo->texture->gl_texturenum); /* FIXME: do the uniforms somewhere else */ shader = glsl_shaders[SHADER_TURB].shader; qglUseProgram(shader); u_gamma = qglGetUniformLocation(shader, "gamma"); u_contrast = qglGetUniformLocation(shader, "contrast"); qglUniform1f(u_gamma, v_gamma.value); qglUniform1f(u_contrast, v_contrast.value); if (r_fastturb.value) { GL_Bind(whitetexture); if (strstr (fa->texinfo->texture->name, "water") || strstr (fa->texinfo->texture->name, "mwat")) col = r_watercolor.color; else if (strstr (fa->texinfo->texture->name, "slime")) col = r_slimecolor.color; else if (strstr (fa->texinfo->texture->name, "lava")) col = r_lavacolor.color; else if (strstr (fa->texinfo->texture->name, "tele")) col = r_telecolor.color; else col = (byte *) &fa->texinfo->texture->flatcolor3ub; glColor3ubv (col); if (wateralpha < 1.0 && wateralpha >= 0) { glEnable (GL_BLEND); col[3] = wateralpha*255; glColor4ubv (col); // 1, 1, 1, wateralpha glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (wateralpha < 0.9) glDepthMask (GL_FALSE); } EmitFlatWaterPoly (fa); if (wateralpha < 1.0 && wateralpha >= 0) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glColor3ubv (color_white); glDisable (GL_BLEND); if (wateralpha < 0.9) glDepthMask (GL_TRUE); } glColor3ubv (color_white); } else { for (p = fa->polys; p; p = p->next) { glBegin(GL_POLYGON); for (i = 0, v = p->verts[0]; i < p->numverts; i++, v += VERTEXSIZE) { os = v[3]; ot = v[4]; s = os + SINTABLE_APPROX(ot * 2 + r_refdef2.time); s *= (1.0 / 64); t = ot + SINTABLE_APPROX(os * 2 + r_refdef2.time); t *= (1.0 / 64); //VULT RIPPLE : Not sure where this came from first, but I've seen in it more than one engine //I got this one from the QMB engine though VectorCopy(v, nv); //Over 20 this setting gets pretty cheaty if (amf_waterripple.value && (cls.demoplayback || cl.spectator) && !strstr (fa->texinfo->texture->name, "tele")) nv[2] = v[2] + (bound(0, amf_waterripple.value, 20)) *sin(v[0]*0.02+r_refdef2.time)*sin(v[1]*0.02+r_refdef2.time)*sin(v[2]*0.02+r_refdef2.time); glTexCoord2f (s, t); glVertex3fv (nv); } glEnd(); } } qglUseProgram(0); if (gl_fogenable.value) glDisable(GL_FOG); }