void Shader::bind(const Shader* shader) { ensureGlContext(); // Make sure that we can use shaders if (!isAvailable()) { err() << "Failed to bind or unbind shader: your system doesn't support shaders " << "(you should test Shader::isAvailable() before trying to use the Shader class)" << std::endl; return; } if (shader && shader->m_shaderProgram) { // Enable the program glCheck(GLEXT_glUseProgramObject(castToGlHandle(shader->m_shaderProgram))); // Bind the textures shader->bindTextures(); // Bind the current texture if (shader->m_currentTexture != -1) glCheck(GLEXT_glUniform1i(shader->m_currentTexture, 0)); } else { // Bind no shader glCheck(GLEXT_glUseProgramObject(0)); } }
Shader::~Shader() { ensureGlContext(); // Destroy effect program if (m_shaderProgram) glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram))); }
//////////////////////////////////////////////////////////// /// \brief Constructor: set up state before uniform is set /// //////////////////////////////////////////////////////////// UniformBinder(Shader& shader, const std::string& name) : savedProgram(0), currentProgram(castToGlHandle(shader.m_shaderProgram)), location(-1) { if (currentProgram) { ensureGlContext(); // Enable program object glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT)); if (currentProgram != savedProgram) glCheck(GLEXT_glUseProgramObject(currentProgram)); // Store uniform location for further use outside constructor location = shader.getUniformLocation(name); } }
int Shader::getUniformLocation(const std::string& name) { // Check the cache UniformTable::const_iterator it = m_uniforms.find(name); if (it != m_uniforms.end()) { // Already in cache, return it return it->second; } else { // Not in cache, request the location from OpenGL int location = GLEXT_glGetUniformLocation(castToGlHandle(m_shaderProgram), name.c_str()); m_uniforms.insert(std::make_pair(name, location)); if (location == -1) err() << "Parameter \"" << name << "\" not found in shader" << std::endl; return location; } }
void Shader::setParameter(const std::string& name, const Transform& transform) { if (m_shaderProgram) { ensureGlContext(); // Enable program GLEXT_GLhandle program; glCheck(program = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT)); glCheck(GLEXT_glUseProgramObject(castToGlHandle(m_shaderProgram))); // Get parameter location and assign it new values GLint location = getParamLocation(name); if (location != -1) { glCheck(GLEXT_glUniformMatrix4fv(location, 1, GL_FALSE, transform.getMatrix())); } // Disable program glCheck(GLEXT_glUseProgramObject(program)); } }
void Shader::setParameter(const std::string& name, float x, float y, float z, float w) { if (m_shaderProgram) { ensureGlContext(); // Enable program GLEXT_GLhandle program; glCheck(program = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT)); glCheck(GLEXT_glUseProgramObject(castToGlHandle(m_shaderProgram))); // Get parameter location and assign it new values GLint location = getParamLocation(name); if (location != -1) { glCheck(GLEXT_glUniform4f(location, x, y, z, w)); } // Disable program glCheck(GLEXT_glUseProgramObject(program)); } }
bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCode) { ensureGlContext(); // First make sure that we can use shaders if (!isAvailable()) { err() << "Failed to create a shader: your system doesn't support shaders " << "(you should test Shader::isAvailable() before trying to use the Shader class)" << std::endl; return false; } // Destroy the shader if it was already created if (m_shaderProgram) { glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram))); m_shaderProgram = 0; } // Reset the internal state m_currentTexture = -1; m_textures.clear(); m_uniforms.clear(); // Create the program GLEXT_GLhandle shaderProgram; glCheck(shaderProgram = GLEXT_glCreateProgramObject()); // Create the vertex shader if needed if (vertexShaderCode) { // Create and compile the shader GLEXT_GLhandle vertexShader; glCheck(vertexShader = GLEXT_glCreateShaderObject(GLEXT_GL_VERTEX_SHADER)); glCheck(GLEXT_glShaderSource(vertexShader, 1, &vertexShaderCode, NULL)); glCheck(GLEXT_glCompileShader(vertexShader)); // Check the compile log GLint success; glCheck(GLEXT_glGetObjectParameteriv(vertexShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success)); if (success == GL_FALSE) { char log[1024]; glCheck(GLEXT_glGetInfoLog(vertexShader, sizeof(log), 0, log)); err() << "Failed to compile vertex shader:" << std::endl << log << std::endl; glCheck(GLEXT_glDeleteObject(vertexShader)); glCheck(GLEXT_glDeleteObject(shaderProgram)); return false; } // Attach the shader to the program, and delete it (not needed anymore) glCheck(GLEXT_glAttachObject(shaderProgram, vertexShader)); glCheck(GLEXT_glDeleteObject(vertexShader)); } // Create the fragment shader if needed if (fragmentShaderCode) { // Create and compile the shader GLEXT_GLhandle fragmentShader; glCheck(fragmentShader = GLEXT_glCreateShaderObject(GLEXT_GL_FRAGMENT_SHADER)); glCheck(GLEXT_glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL)); glCheck(GLEXT_glCompileShader(fragmentShader)); // Check the compile log GLint success; glCheck(GLEXT_glGetObjectParameteriv(fragmentShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success)); if (success == GL_FALSE) { char log[1024]; glCheck(GLEXT_glGetInfoLog(fragmentShader, sizeof(log), 0, log)); err() << "Failed to compile fragment shader:" << std::endl << log << std::endl; glCheck(GLEXT_glDeleteObject(fragmentShader)); glCheck(GLEXT_glDeleteObject(shaderProgram)); return false; } // Attach the shader to the program, and delete it (not needed anymore) glCheck(GLEXT_glAttachObject(shaderProgram, fragmentShader)); glCheck(GLEXT_glDeleteObject(fragmentShader)); } // Link the program glCheck(GLEXT_glLinkProgram(shaderProgram)); // Check the link log GLint success; glCheck(GLEXT_glGetObjectParameteriv(shaderProgram, GLEXT_GL_OBJECT_LINK_STATUS, &success)); if (success == GL_FALSE) { char log[1024]; glCheck(GLEXT_glGetInfoLog(shaderProgram, sizeof(log), 0, log)); err() << "Failed to link shader:" << std::endl << log << std::endl; glCheck(GLEXT_glDeleteObject(shaderProgram)); return false; } m_shaderProgram = castFromGlHandle(shaderProgram); // Force an OpenGL flush, so that the shader will appear updated // in all contexts immediately (solves problems in multi-threaded apps) glCheck(glFlush()); return true; }