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 sourcesource30Matrix3?pp sourceThread?pp sourcearm biquad ?scade ?1 ?st q31? sourcearm conv ?2? sourcearm mat mult q15? sourceResource 8inl sourcearm fir lattice init q31? sourcearm fir ?cimate ?st q15? sourcesource11arm correlate ?st q15? sourceconnector?s sourcesource8register? sourcepassing values sourcearm iir lattice init ?2? sourcewięcej podobnych podstron