00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) 00005 // 00006 // This software is provided 'as-is', without any express or implied warranty. 00007 // In no event will the authors be held liable for any damages arising from the use of this software. 00008 // 00009 // Permission is granted to anyone to use this software for any purpose, 00010 // including commercial applications, and to alter it and redistribute it freely, 00011 // subject to the following restrictions: 00012 // 00013 // 1. The origin of this software must not be misrepresented; 00014 // you must not claim that you wrote the original software. 00015 // If you use this software in a product, an acknowledgment 00016 // in the product documentation would be appreciated but is not required. 00017 // 00018 // 2. Altered source versions must be plainly marked as such, 00019 // and must not be misrepresented as being the original software. 00020 // 00021 // 3. This notice may not be removed or altered from any source distribution. 00022 // 00024 00025 00027 // Headers 00029 #include <SFML/Graphics/Shader.hpp> 00030 #include <SFML/Graphics/GLCheck.hpp> 00031 #include <SFML/System/Err.hpp> 00032 #include <fstream> 00033 #include <sstream> 00034 00035 00036 namespace sf 00037 { 00039 // Static member data 00041 const Image Shader::CurrentTexture; 00042 00043 00045 Shader::Shader() : 00046 myShaderProgram (0), 00047 myCurrentTexture(-1) 00048 { 00049 00050 } 00051 00052 00054 Shader::Shader(const Shader& copy) : 00055 myShaderProgram (0), 00056 myCurrentTexture(copy.myCurrentTexture), 00057 myTextures (copy.myTextures), 00058 myFragmentShader(copy.myFragmentShader) 00059 { 00060 // Create the shaders and the program 00061 if (copy.myShaderProgram) 00062 CompileProgram(); 00063 } 00064 00065 00067 Shader::~Shader() 00068 { 00069 // Destroy effect program 00070 if (myShaderProgram) 00071 GLCheck(glDeleteObjectARB(myShaderProgram)); 00072 } 00073 00074 00076 bool Shader::LoadFromFile(const std::string& filename) 00077 { 00078 // Open the file 00079 std::ifstream file(filename.c_str()); 00080 if (!file) 00081 { 00082 Err() << "Failed to open shader file \"" << filename << "\"" << std::endl; 00083 return false; 00084 } 00085 00086 // Read the shader code from the file 00087 std::string line; 00088 while (std::getline(file, line)) 00089 myFragmentShader += line + "\n"; 00090 00091 // Create the shaders and the program 00092 return CompileProgram(); 00093 } 00094 00095 00097 bool Shader::LoadFromMemory(const std::string& shader) 00098 { 00099 // Save the shader code 00100 myFragmentShader = shader; 00101 00102 // Create the shaders and the program 00103 return CompileProgram(); 00104 } 00105 00106 00108 void Shader::SetParameter(const std::string& name, float x) 00109 { 00110 if (myShaderProgram) 00111 { 00112 // Enable program 00113 GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); 00114 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00115 00116 // Get parameter location and assign it new values 00117 GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str()); 00118 if (location != -1) 00119 GLCheck(glUniform1fARB(location, x)); 00120 else 00121 Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; 00122 00123 // Disable program 00124 GLCheck(glUseProgramObjectARB(program)); 00125 } 00126 } 00127 00128 00130 void Shader::SetParameter(const std::string& name, float x, float y) 00131 { 00132 if (myShaderProgram) 00133 { 00134 // Enable program 00135 GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); 00136 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00137 00138 // Get parameter location and assign it new values 00139 GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str()); 00140 if (location != -1) 00141 GLCheck(glUniform2fARB(location, x, y)); 00142 else 00143 Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; 00144 00145 // Disable program 00146 GLCheck(glUseProgramObjectARB(program)); 00147 } 00148 } 00149 00150 00152 void Shader::SetParameter(const std::string& name, float x, float y, float z) 00153 { 00154 if (myShaderProgram) 00155 { 00156 // Enable program 00157 GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); 00158 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00159 00160 // Get parameter location and assign it new values 00161 GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str()); 00162 if (location != -1) 00163 GLCheck(glUniform3fARB(location, x, y, z)); 00164 else 00165 Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; 00166 00167 // Disable program 00168 GLCheck(glUseProgramObjectARB(program)); 00169 } 00170 } 00171 00172 00174 void Shader::SetParameter(const std::string& name, float x, float y, float z, float w) 00175 { 00176 if (myShaderProgram) 00177 { 00178 // Enable program 00179 GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); 00180 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00181 00182 // Get parameter location and assign it new values 00183 GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str()); 00184 if (location != -1) 00185 GLCheck(glUniform4fARB(location, x, y, z, w)); 00186 else 00187 Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; 00188 00189 // Disable program 00190 GLCheck(glUseProgramObjectARB(program)); 00191 } 00192 } 00193 00194 00196 void Shader::SetParameter(const std::string& name, const Vector2f& v) 00197 { 00198 SetParameter(name, v.x, v.y); 00199 } 00200 00201 00203 void Shader::SetParameter(const std::string& name, const Vector3f& v) 00204 { 00205 SetParameter(name, v.x, v.y, v.z); 00206 } 00207 00208 00210 void Shader::SetTexture(const std::string& name, const Image& texture) 00211 { 00212 if (myShaderProgram) 00213 { 00214 // Check if there is a texture unit available 00215 GLint maxUnits; 00216 GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits)); 00217 if (myTextures.size() + 1 >= static_cast<std::size_t>(maxUnits)) 00218 { 00219 Err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl; 00220 return; 00221 } 00222 00223 // Make sure the given name is a valid variable in the effect 00224 int location = glGetUniformLocationARB(myShaderProgram, name.c_str()); 00225 if (location == -1) 00226 { 00227 Err() << "Texture \"" << name << "\" not found in shader" << std::endl; 00228 return; 00229 } 00230 00231 // Store the texture for later use 00232 if (&texture != &CurrentTexture) 00233 myTextures[location] = &texture; 00234 else 00235 myCurrentTexture = location; 00236 } 00237 } 00238 00239 00241 void Shader::Bind() const 00242 { 00243 if (myShaderProgram) 00244 { 00245 // Enable the program 00246 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00247 00248 // Bind the textures 00249 BindTextures(); 00250 00251 // Make sure that the texture unit which is left active is the number 0 00252 GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB)); 00253 00254 // Bind the current texture 00255 if (myCurrentTexture != -1) 00256 GLCheck(glUniform1iARB(myCurrentTexture, 0)); 00257 } 00258 } 00259 00260 00262 void Shader::Unbind() const 00263 { 00264 GLCheck(glUseProgramObjectARB(0)); 00265 } 00266 00267 00269 Shader& Shader::operator =(const Shader& right) 00270 { 00271 Shader temp(right); 00272 00273 std::swap(myShaderProgram, temp.myShaderProgram); 00274 std::swap(myCurrentTexture, temp.myCurrentTexture); 00275 std::swap(myTextures, temp.myTextures); 00276 std::swap(myFragmentShader, temp.myFragmentShader); 00277 00278 return *this; 00279 } 00280 00281 00283 bool Shader::IsAvailable() 00284 { 00285 // Make sure that GLEW is initialized 00286 priv::EnsureGlewInit(); 00287 00288 return GLEW_ARB_shading_language_100 && 00289 GLEW_ARB_shader_objects && 00290 GLEW_ARB_vertex_shader && 00291 GLEW_ARB_fragment_shader; 00292 } 00293 00294 00296 bool Shader::CompileProgram() 00297 { 00298 // First make sure that we can use shaders 00299 if (!IsAvailable()) 00300 { 00301 Err() << "Failed to create a shader: your system doesn't support shaders " 00302 << "(you should test Shader::IsAvailable() before trying to use the Shader class)" << std::endl; 00303 return false; 00304 } 00305 00306 // Make sure that GLEW is initialized (extra safety -- it is already done in IsAvailable()) 00307 priv::EnsureGlewInit(); 00308 00309 // Destroy the shader if it was already created 00310 if (myShaderProgram) 00311 GLCheck(glDeleteObjectARB(myShaderProgram)); 00312 00313 // Define the vertex shader source (we provide it directly as it doesn't have to change) 00314 static const char* vertexSrc = 00315 "void main()" 00316 "{" 00317 " gl_TexCoord[0] = gl_MultiTexCoord0;" 00318 " gl_FrontColor = gl_Color;" 00319 " gl_Position = ftransform();" 00320 "}"; 00321 00322 // Create the program 00323 myShaderProgram = glCreateProgramObjectARB(); 00324 00325 // Create the shaders 00326 GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); 00327 GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 00328 00329 // Compile them 00330 const char* fragmentSrc = myFragmentShader.c_str(); 00331 GLCheck(glShaderSourceARB(vertexShader, 1, &vertexSrc, NULL)); 00332 GLCheck(glShaderSourceARB(fragmentShader, 1, &fragmentSrc, NULL)); 00333 GLCheck(glCompileShaderARB(vertexShader)); 00334 GLCheck(glCompileShaderARB(fragmentShader)); 00335 00336 // Check the compile logs 00337 GLint success; 00338 GLCheck(glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); 00339 if (success == GL_FALSE) 00340 { 00341 char log[1024]; 00342 GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log)); 00343 Err() << "Failed to compile shader:" << std::endl 00344 << log << std::endl; 00345 GLCheck(glDeleteObjectARB(vertexShader)); 00346 GLCheck(glDeleteObjectARB(fragmentShader)); 00347 GLCheck(glDeleteObjectARB(myShaderProgram)); 00348 myShaderProgram = 0; 00349 return false; 00350 } 00351 GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success)); 00352 if (success == GL_FALSE) 00353 { 00354 char log[1024]; 00355 GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log)); 00356 Err() << "Failed to compile shader:" << std::endl 00357 << log << std::endl; 00358 GLCheck(glDeleteObjectARB(vertexShader)); 00359 GLCheck(glDeleteObjectARB(fragmentShader)); 00360 GLCheck(glDeleteObjectARB(myShaderProgram)); 00361 myShaderProgram = 0; 00362 return false; 00363 } 00364 00365 // Attach the shaders to the program 00366 GLCheck(glAttachObjectARB(myShaderProgram, vertexShader)); 00367 GLCheck(glAttachObjectARB(myShaderProgram, fragmentShader)); 00368 00369 // We can now delete the shaders 00370 GLCheck(glDeleteObjectARB(vertexShader)); 00371 GLCheck(glDeleteObjectARB(fragmentShader)); 00372 00373 // Link the program 00374 GLCheck(glLinkProgramARB(myShaderProgram)); 00375 00376 // Get link log 00377 GLCheck(glGetObjectParameterivARB(myShaderProgram, GL_OBJECT_LINK_STATUS_ARB, &success)); 00378 if (success == GL_FALSE) 00379 { 00380 // Oops... link errors 00381 char log[1024]; 00382 GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(log), 0, log)); 00383 Err() << "Failed to link shader:" << std::endl 00384 << log << std::endl; 00385 GLCheck(glDeleteObjectARB(myShaderProgram)); 00386 myShaderProgram = 0; 00387 return false; 00388 } 00389 00390 return true; 00391 } 00392 00393 00395 void Shader::BindTextures() const 00396 { 00397 TextureTable::const_iterator it = myTextures.begin(); 00398 for (std::size_t i = 0; i < myTextures.size(); ++i) 00399 { 00400 GLint index = static_cast<GLsizei>(i + 1); 00401 GLCheck(glUniform1iARB(it->first, index)); 00402 GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB + index)); 00403 it->second->Bind(); 00404 it++; 00405 } 00406 } 00407 00408 00410 void Shader::Use() const 00411 { 00412 BindTextures(); 00413 } 00414 00415 } // namespace sf
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::