PostFX 8cpp source


SFML - Simple and Fast Multimedia Library Main Page Namespaces Classes Files File List PostFX.cpp00001 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/PostFX.hpp> 00030 #include <SFML/Graphics/RenderWindow.hpp> 00031 #include <SFML/Graphics/GraphicsContext.hpp> 00032 #include <fstream> 00033 #include <iostream> 00034 #include <set> 00035 #include <sstream> 00036 00037 00038 namespace sf 00039 { 00043 PostFX::PostFX() : 00044 myShaderProgram(0) 00045 { 00046 // No filtering on frame buffer 00047 myFrameBuffer.SetSmooth(false); 00048 } 00049 00050 00054 PostFX::PostFX(const PostFX& Copy) : 00055 Drawable (Copy), 00056 myShaderProgram (0), 00057 myTextures (Copy.myTextures), 00058 myFragmentShader(Copy.myFragmentShader), 00059 myFrameBuffer (Copy.myFrameBuffer) 00060 { 00061 // No filtering on frame buffer 00062 myFrameBuffer.SetSmooth(false); 00063 00064 // Create the shaders and the program 00065 if (Copy.myShaderProgram) 00066 CreateProgram(); 00067 } 00068 00069 00073 PostFX::~PostFX() 00074 { 00075 // Destroy effect program 00076 if (myShaderProgram) 00077 { 00078 // Make sure we have a valid context 00079 priv::GraphicsContext Ctx; 00080 00081 GLCheck(glDeleteObjectARB(myShaderProgram)); 00082 } 00083 } 00084 00085 00089 bool PostFX::LoadFromFile(const std::string& Filename) 00090 { 00091 // Open the file 00092 std::ifstream File(Filename.c_str()); 00093 if (!File) 00094 { 00095 std::cerr << "Failed to open effect file \"" << Filename << "\"" << std::endl; 00096 return false; 00097 } 00098 00099 // Apply the preprocessing pass to the fragment shader code 00100 myFragmentShader = PreprocessEffect(File); 00101 00102 // Create the shaders and the program 00103 CreateProgram(); 00104 00105 return myShaderProgram != 0; 00106 } 00107 00108 00112 bool PostFX::LoadFromMemory(const std::string& Effect) 00113 { 00114 // Open a stream and copy the effect code 00115 std::istringstream Stream(Effect.c_str()); 00116 00117 // Apply the preprocessing pass to the fragment shader code 00118 myFragmentShader = PreprocessEffect(Stream); 00119 00120 // Create the shaders and the program 00121 CreateProgram(); 00122 00123 return myShaderProgram != 0; 00124 } 00125 00126 00130 void PostFX::SetParameter(const std::string& Name, float X) 00131 { 00132 if (myShaderProgram) 00133 { 00134 // Enable program 00135 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00136 00137 // Get parameter location and assign it new values 00138 GLint Location = glGetUniformLocationARB(myShaderProgram, Name.c_str()); 00139 if (Location != -1) 00140 GLCheck(glUniform1fARB(Location, X)); 00141 else 00142 std::cerr << "Parameter \"" << Name << "\" not found in post-effect" << std::endl; 00143 00144 // Disable program 00145 GLCheck(glUseProgramObjectARB(0)); 00146 } 00147 } 00148 00149 00153 void PostFX::SetParameter(const std::string& Name, float X, float Y) 00154 { 00155 if (myShaderProgram) 00156 { 00157 // Enable program 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(glUniform2fARB(Location, X, Y)); 00164 else 00165 std::cerr << "Parameter \"" << Name << "\" not found in post-effect" << std::endl; 00166 00167 // Disable program 00168 GLCheck(glUseProgramObjectARB(0)); 00169 } 00170 } 00171 00172 00176 void PostFX::SetParameter(const std::string& Name, float X, float Y, float Z) 00177 { 00178 if (myShaderProgram) 00179 { 00180 // Enable program 00181 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00182 00183 // Get parameter location and assign it new values 00184 GLint Location = glGetUniformLocationARB(myShaderProgram, Name.c_str()); 00185 if (Location != -1) 00186 GLCheck(glUniform3fARB(Location, X, Y, Z)); 00187 else 00188 std::cerr << "Parameter \"" << Name << "\" not found in post-effect" << std::endl; 00189 00190 // Disable program 00191 GLCheck(glUseProgramObjectARB(0)); 00192 } 00193 } 00194 00195 00199 void PostFX::SetParameter(const std::string& Name, float X, float Y, float Z, float W) 00200 { 00201 if (myShaderProgram) 00202 { 00203 // Enable program 00204 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00205 00206 // Get parameter location and assign it new values 00207 GLint Location = glGetUniformLocationARB(myShaderProgram, Name.c_str()); 00208 if (Location != -1) 00209 GLCheck(glUniform4fARB(Location, X, Y, Z, W)); 00210 else 00211 std::cerr << "Parameter \"" << Name << "\" not found in post-effect" << std::endl; 00212 00213 // Disable program 00214 GLCheck(glUseProgramObjectARB(0)); 00215 } 00216 } 00217 00218 00222 void PostFX::SetTexture(const std::string& Name, Image* Texture) 00223 { 00224 // Check that the current texture unit is available 00225 GLint MaxUnits; 00226 GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &MaxUnits)); 00227 if (myTextures.size() >= static_cast<std::size_t>(MaxUnits)) 00228 { 00229 std::cerr << "Impossible to use texture \"" << Name << "\" for post-effect : all available texture units are used" << std::endl; 00230 return; 00231 } 00232 00233 // Make sure the given name is a valid variable in the effect 00234 int Location = glGetUniformLocationARB(myShaderProgram, Name.c_str()); 00235 if (Location == -1) 00236 { 00237 std::cerr << "Texture \"" << Name << "\" not found in post-effect" << std::endl; 00238 return; 00239 } 00240 00241 // Store the texture for later use 00242 myTextures[Name] = Texture ? Texture : &myFrameBuffer; 00243 } 00244 00245 00249 PostFX& PostFX::operator =(const PostFX& Other) 00250 { 00251 PostFX Temp(Other); 00252 00253 std::swap(myShaderProgram, Temp.myShaderProgram); 00254 std::swap(myTextures, Temp.myTextures); 00255 std::swap(myFragmentShader, Temp.myFragmentShader); 00256 std::swap(myFrameBuffer, Temp.myFrameBuffer); 00257 00258 return *this; 00259 } 00260 00261 00265 bool PostFX::CanUsePostFX() 00266 { 00267 // Make sure we have a valid context 00268 priv::GraphicsContext Ctx; 00269 00270 return glewIsSupported("GL_ARB_shading_language_100") != 0 && 00271 glewIsSupported("GL_ARB_shader_objects") != 0 && 00272 glewIsSupported("GL_ARB_vertex_shader") != 0 && 00273 glewIsSupported("GL_ARB_fragment_shader") != 0; 00274 } 00275 00276 00280 void PostFX::Render(RenderTarget& Target) const 00281 { 00282 // Check that we have a valid program 00283 if (!myShaderProgram) 00284 return; 00285 00286 // Copy the current framebuffer pixels to our frame buffer texture 00287 // The ugly cast is temporary until PostFx are rewritten :) 00288 myFrameBuffer.CopyScreen((RenderWindow&)Target); 00289 00290 // Enable program 00291 GLCheck(glUseProgramObjectARB(myShaderProgram)); 00292 00293 // Bind textures 00294 TextureTable::const_iterator ItTex = myTextures.begin(); 00295 for (std::size_t i = 0; i < myTextures.size(); ++i) 00296 { 00297 int Location = glGetUniformLocationARB(myShaderProgram, ItTex->first.c_str()); 00298 GLCheck(glUniform1iARB(Location, static_cast<GLint>(i))); 00299 GLCheck(glActiveTextureARB(static_cast<GLenum>(GL_TEXTURE0_ARB + i))); 00300 ItTex->second->Bind(); 00301 ItTex++; 00302 } 00303 00304 // Compute the texture coordinates (in case the texture is larger than the screen, or flipped) 00305 IntRect FrameBufferRect(0, 0, myFrameBuffer.GetWidth(), myFrameBuffer.GetHeight()); 00306 FloatRect TexCoords = myFrameBuffer.GetTexCoords(FrameBufferRect); 00307 00308 // Render a fullscreen quad using the effect on our framebuffer 00309 FloatRect Screen = Target.GetView().GetRect(); 00310 glBegin(GL_QUADS); 00311 glTexCoord2f(TexCoords.Left, TexCoords.Top); glVertex2f(Screen.Left, Screen.Bottom); 00312 glTexCoord2f(TexCoords.Right, TexCoords.Top); glVertex2f(Screen.Right, Screen.Bottom); 00313 glTexCoord2f(TexCoords.Right, TexCoords.Bottom); glVertex2f(Screen.Right, Screen.Top); 00314 glTexCoord2f(TexCoords.Left, TexCoords.Bottom); glVertex2f(Screen.Left, Screen.Top); 00315 glEnd(); 00316 00317 // Disable program 00318 GLCheck(glUseProgramObjectARB(0)); 00319 00320 // Disable texture units 00321 for (std::size_t i = 0; i < myTextures.size(); ++i) 00322 { 00323 GLCheck(glActiveTextureARB(static_cast<GLenum>(GL_TEXTURE0_ARB + i))); 00324 GLCheck(glBindTexture(GL_TEXTURE_2D, 0)); 00325 } 00326 GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB)); 00327 } 00328 00329 00334 std::string PostFX::PreprocessEffect(std::istream& File) 00335 { 00336 // Initialize output string 00337 std::set<std::string> myTextures; 00338 std::string Out = ""; 00339 00340 // Variable declarations 00341 std::string Line; 00342 while (std::getline(File, Line) && (Line.substr(0, 6) != "effect")) 00343 { 00344 // Remove the ending '\r', if any 00345 if (!Line.empty() && (Line[Line.size() - 1] == '\r')) 00346 Line.erase(Line.size() - 1); 00347 00348 // Skip empty lines 00349 if (Line == "") 00350 continue; 00351 00352 // Extract variables type and name and convert them 00353 std::string Type, Name; 00354 std::istringstream iss(Line); 00355 if (!(iss >> Type >> Name)) 00356 { 00357 std::cerr << "Post-effect error : invalid declaration (should be \"[type][name]\")" << std::endl 00358 << "> " << Line << std::endl; 00359 return ""; 00360 } 00361 00362 if (Type == "texture") 00363 { 00364 // Textures need some checking and conversion 00365 if (myTextures.find(Name) != myTextures.end()) 00366 { 00367 std::cerr << "Post-effect error : texture \"" << Name << "\" already exists" << std::endl; 00368 return ""; 00369 } 00370 00371 Out += "uniform sampler2D " + Name + ";\n"; 00372 myTextures.insert(Name); 00373 } 00374 else 00375 { 00376 // Other types are just copied to output with "uniform" prefix 00377 Out += "uniform " + Type + " " + Name + ";\n"; 00378 } 00379 } 00380 00381 // Effect code 00382 Out += "void main()\n"; 00383 while (std::getline(File, Line)) 00384 { 00385 // Replace any texture lookup "T(" by "texture2D(T, " 00386 for (std::set<std::string>::const_iterator i = myTextures.begin(); i != myTextures.end(); ++i) 00387 { 00388 std::string::size_type Pos = Line.find(*i); 00389 if (Pos != std::string::npos) 00390 Line.replace(Pos, i->size() + 1, "texture2D(" + *i + ", "); 00391 } 00392 00393 // Replace "_in" by "gl_TexCoord[0].xy" 00394 for (std::string::size_type Pos = Line.find("_in"); Pos != std::string::npos; Pos = Line.find("_in")) 00395 Line.replace(Pos, 3, "gl_TexCoord[0].xy"); 00396 00397 // Replace "_out" by "gl_FragColor" 00398 for (std::string::size_type Pos = Line.find("_out"); Pos != std::string::npos; Pos = Line.find("_out")) 00399 Line.replace(Pos, 4, "gl_FragColor"); 00400 00401 // Write modified line to output string 00402 Out += Line + "\n"; 00403 } 00404 00405 return Out; 00406 } 00407 00408 00412 void PostFX::CreateProgram() 00413 { 00414 // Make sure we have a valid context 00415 priv::GraphicsContext Ctx; 00416 00417 // Check that we can use post-FX ! 00418 if (!CanUsePostFX()) 00419 { 00420 std::cerr << "Failed to create a PostFX : your system doesn't support effects" << std::endl; 00421 return; 00422 } 00423 00424 // Destroy effect program if it was already created 00425 if (myShaderProgram) 00426 GLCheck(glDeleteObjectARB(myShaderProgram)); 00427 00428 // Define vertex shader source (we provide it directly as it doesn't have to change) 00429 static const std::string VertexShaderSrc = 00430 "void main()" 00431 "{" 00432 " gl_TexCoord[0] = gl_MultiTexCoord0;" 00433 " gl_Position = ftransform();" 00434 "}"; 00435 00436 // Create the program 00437 myShaderProgram = glCreateProgramObjectARB(); 00438 00439 // Create the shaders 00440 GLhandleARB VertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); 00441 GLhandleARB FragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 00442 00443 // Compile them 00444 const char* VertexSrc = VertexShaderSrc.c_str(); 00445 const char* FragmentSrc = myFragmentShader.c_str(); 00446 GLCheck(glShaderSourceARB(VertexShader, 1, &VertexSrc, NULL)); 00447 GLCheck(glShaderSourceARB(FragmentShader, 1, &FragmentSrc, NULL)); 00448 GLCheck(glCompileShaderARB(VertexShader)); 00449 GLCheck(glCompileShaderARB(FragmentShader)); 00450 00451 // Check the compile logs 00452 GLint Success; 00453 GLCheck(glGetObjectParameterivARB(VertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &Success)); 00454 if (Success == GL_FALSE) 00455 { 00456 char CompileLog[1024]; 00457 GLCheck(glGetInfoLogARB(VertexShader, sizeof(CompileLog), 0, CompileLog)); 00458 std::cerr << "Failed to compile post-effect :" << std::endl 00459 << CompileLog << std::endl; 00460 GLCheck(glDeleteObjectARB(VertexShader)); 00461 GLCheck(glDeleteObjectARB(FragmentShader)); 00462 GLCheck(glDeleteObjectARB(myShaderProgram)); 00463 myShaderProgram = 0; 00464 return; 00465 } 00466 GLCheck(glGetObjectParameterivARB(FragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &Success)); 00467 if (Success == GL_FALSE) 00468 { 00469 char CompileLog[1024]; 00470 GLCheck(glGetInfoLogARB(FragmentShader, sizeof(CompileLog), 0, CompileLog)); 00471 std::cerr << "Failed to compile post-effect :" << std::endl 00472 << CompileLog << std::endl; 00473 GLCheck(glDeleteObjectARB(VertexShader)); 00474 GLCheck(glDeleteObjectARB(FragmentShader)); 00475 GLCheck(glDeleteObjectARB(myShaderProgram)); 00476 myShaderProgram = 0; 00477 return; 00478 } 00479 00480 // Attach the shaders to the program 00481 GLCheck(glAttachObjectARB(myShaderProgram, VertexShader)); 00482 GLCheck(glAttachObjectARB(myShaderProgram, FragmentShader)); 00483 00484 // We can now delete the shaders 00485 GLCheck(glDeleteObjectARB(VertexShader)); 00486 GLCheck(glDeleteObjectARB(FragmentShader)); 00487 00488 // Link the program 00489 GLCheck(glLinkProgramARB(myShaderProgram)); 00490 00491 // Get link log 00492 GLCheck(glGetObjectParameterivARB(myShaderProgram, GL_OBJECT_LINK_STATUS_ARB, &Success)); 00493 if (Success == GL_FALSE) 00494 { 00495 // Oops... link errors 00496 char LinkLog[1024]; 00497 GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(LinkLog), 0, LinkLog)); 00498 std::cerr << "Failed to link post-effect :" << std::endl 00499 << LinkLog << std::endl; 00500 GLCheck(glDeleteObjectARB(myShaderProgram)); 00501 myShaderProgram = 0; 00502 return; 00503 } 00504 } 00505 00506 } // namespace sf  ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  :: 

Wyszukiwarka

Podobne podstrony:
PostFX 8hpp source
source30
Matrix3?pp source
Thread?pp source
arm biquad ?scade ?1 ?st q31? source
arm conv ?2? source
arm mat mult q15? source
Resource 8inl source
arm fir lattice init q31? source
arm fir ?cimate ?st q15? source
source11
arm correlate ?st q15? source
connector?s source
source8
register? source
passing values source
arm iir lattice init ?2? source

więcej podobnych podstron