void Shader::SetParameter(const std::string& name, float x) { if (myShaderProgram) { EnsureGlContext(); // Enable program GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); GLCheck(glUseProgramObjectARB(myShaderProgram)); // Get parameter location and assign it new values GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str()); if (location != -1) GLCheck(glUniform1fARB(location, x)); else Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; // Disable program GLCheck(glUseProgramObjectARB(program)); } }
unsigned int Texture::GetValidSize(unsigned int size) { EnsureGlContext(); // Make sure that GLEW is initialized priv::EnsureGlewInit(); if (GLEW_ARB_texture_non_power_of_two) { // If hardware supports NPOT textures, then just return the unmodified size return size; } else { // If hardware doesn't support NPOT textures, we calculate the nearest power of two unsigned int powerOfTwo = 1; while (powerOfTwo < size) powerOfTwo *= 2; return powerOfTwo; } }
void Shader::SetTexture(const std::string& name, const Image& texture) { if (myShaderProgram) { EnsureGlContext(); // Find the location of the variable in the shader int location = glGetUniformLocationARB(myShaderProgram, name.c_str()); if (location == -1) { Err() << "Texture \"" << name << "\" not found in shader" << std::endl; return; } // Store the location -> texture mapping TextureTable::iterator it = myTextures.find(location); if (it == myTextures.end()) { // New entry, make sure there are enough texture units GLint maxUnits; GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits)); if (myTextures.size() + 1 >= static_cast<std::size_t>(maxUnits)) { Err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl; return; } myTextures[location] = &texture; } else { // Location already used, just replace the texture it->second = &texture; } } }
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 (myShaderProgram) GLCheck(glDeleteObjectARB(myShaderProgram)); // Create the program myShaderProgram = glCreateProgramObjectARB(); // Create the vertex shader if needed if (vertexShaderCode) { // Create and compile the shader GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); GLCheck(glShaderSourceARB(vertexShader, 1, &vertexShaderCode, NULL)); GLCheck(glCompileShaderARB(vertexShader)); // Check the compile log GLint success; GLCheck(glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); if (success == GL_FALSE) { char log[1024]; GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log)); Err() << "Failed to compile vertex shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(vertexShader)); GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } // Attach the shader to the program, and delete it (not needed anymore) GLCheck(glAttachObjectARB(myShaderProgram, vertexShader)); GLCheck(glDeleteObjectARB(vertexShader)); } // Create the fragment shader if needed if (fragmentShaderCode) { // Create and compile the shader GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); GLCheck(glShaderSourceARB(fragmentShader, 1, &fragmentShaderCode, NULL)); GLCheck(glCompileShaderARB(fragmentShader)); // Check the compile log GLint success; GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); if (success == GL_FALSE) { char log[1024]; GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log)); Err() << "Failed to compile fragment shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(fragmentShader)); GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } // Attach the shader to the program, and delete it (not needed anymore) GLCheck(glAttachObjectARB(myShaderProgram, fragmentShader)); GLCheck(glDeleteObjectARB(fragmentShader)); } // Link the program GLCheck(glLinkProgramARB(myShaderProgram)); // Check the link log GLint success; GLCheck(glGetObjectParameterivARB(myShaderProgram, GL_OBJECT_LINK_STATUS_ARB, &success)); if (success == GL_FALSE) { char log[1024]; GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(log), 0, log)); Err() << "Failed to link shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } return true; }
void Shader::Unbind() const { EnsureGlContext(); GLCheck(glUseProgramObjectARB(0)); }
bool Shader::CompileProgram() { 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 (myShaderProgram) GLCheck(glDeleteObjectARB(myShaderProgram)); // Define the vertex shader source (we provide it directly as it doesn't have to change) static const char* vertexSrc = "void main()" "{" " gl_TexCoord[0] = gl_MultiTexCoord0;" " gl_FrontColor = gl_Color;" " gl_Position = ftransform();" "}"; // Create the program myShaderProgram = glCreateProgramObjectARB(); // Create the shaders GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); // Compile them const char* fragmentSrc = myFragmentShader.c_str(); GLCheck(glShaderSourceARB(vertexShader, 1, &vertexSrc, NULL)); GLCheck(glShaderSourceARB(fragmentShader, 1, &fragmentSrc, NULL)); GLCheck(glCompileShaderARB(vertexShader)); GLCheck(glCompileShaderARB(fragmentShader)); // Check the compile logs GLint success; GLCheck(glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); if (success == GL_FALSE) { char log[1024]; GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log)); Err() << "Failed to compile shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(vertexShader)); GLCheck(glDeleteObjectARB(fragmentShader)); GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); if (success == GL_FALSE) { char log[1024]; GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log)); Err() << "Failed to compile shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(vertexShader)); GLCheck(glDeleteObjectARB(fragmentShader)); GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } // Attach the shaders to the program GLCheck(glAttachObjectARB(myShaderProgram, vertexShader)); GLCheck(glAttachObjectARB(myShaderProgram, fragmentShader)); // We can now delete the shaders GLCheck(glDeleteObjectARB(vertexShader)); GLCheck(glDeleteObjectARB(fragmentShader)); // Link the program GLCheck(glLinkProgramARB(myShaderProgram)); // Get link log GLCheck(glGetObjectParameterivARB(myShaderProgram, GL_OBJECT_LINK_STATUS_ARB, &success)); if (success == GL_FALSE) { // Oops... link errors char log[1024]; GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(log), 0, log)); Err() << "Failed to link shader:" << std::endl << log << std::endl; GLCheck(glDeleteObjectARB(myShaderProgram)); myShaderProgram = 0; return false; } return true; }