//////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// #include #include #include void DisplayError(); //////////////////////////////////////////////////////////// /// A class to simplify shader selection /// //////////////////////////////////////////////////////////// class ShaderSelector { public : // Constructor ShaderSelector(std::map& owner, const std::string& shader) : myOwner (&owner), myIterator(owner.find(shader)) { } // Select the previous shader void GotoPrevious() { if (myIterator == myOwner->begin()) myIterator = myOwner->end(); myIterator--; } // Select the next shader void GotoNext() { myIterator++; if (myIterator == myOwner->end()) myIterator = myOwner->begin(); } // Update the shader parameters void Update(float x, float y) { if (myIterator->first == "blur") myIterator->second.SetParameter("offset", x * y * 0.03f); else if (myIterator->first == "colorize") myIterator->second.SetParameter("color", 0.3f, x, y); else if (myIterator->first == "edge") myIterator->second.SetParameter("threshold", x * y); else if (myIterator->first == "fisheye") myIterator->second.SetParameter("mouse", x, y); else if (myIterator->first == "wave") myIterator->second.SetParameter("offset", x, y); else if (myIterator->first == "pixelate") myIterator->second.SetParameter("mouse", x, y); } // Get the name of the current shader const std::string& GetName() const { return myIterator->first; } // Get the current shader const sf::Shader& GetShader() const { return myIterator->second; } private : std::map* myOwner; std::map::iterator myIterator; }; //////////////////////////////////////////////////////////// /// Entry point of application /// /// \return Application exit code /// //////////////////////////////////////////////////////////// int main() { // Check that the system can use shaders if (sf::Shader::IsAvailable() == false) { DisplayError(); return EXIT_SUCCESS; } // Create the main window sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Shader"); // Create the render image sf::RenderImage image; if (!image.Create(window.GetWidth(), window.GetHeight())) return EXIT_FAILURE; // Load a background image to display sf::Image backgroundImage; if (!backgroundImage.LoadFromFile("datas/shader/background.jpg")) return EXIT_FAILURE; sf::Sprite background(backgroundImage); backgroundImage.SetSmooth(false); // Load a sprite which we'll move into the scene sf::Image entityImage; if (!entityImage.LoadFromFile("datas/shader/sprite.png")) return EXIT_FAILURE; sf::Sprite entity(entityImage); // Load the text font sf::Font font; if (!font.LoadFromFile("datas/shader/arial.ttf", 20)) return EXIT_FAILURE; // Load the image needed for the wave shader sf::Image waveImage; if (!waveImage.LoadFromFile("datas/shader/wave.jpg")) return EXIT_FAILURE; // Load all shaders std::map shaders; if (!shaders["nothing"].LoadFromFile("datas/shader/nothing.sfx")) return EXIT_FAILURE; if (!shaders["blur"].LoadFromFile("datas/shader/blur.sfx")) return EXIT_FAILURE; if (!shaders["colorize"].LoadFromFile("datas/shader/colorize.sfx")) return EXIT_FAILURE; if (!shaders["edge"].LoadFromFile("datas/shader/edge.sfx")) return EXIT_FAILURE; if (!shaders["fisheye"].LoadFromFile("datas/shader/fisheye.sfx")) return EXIT_FAILURE; if (!shaders["wave"].LoadFromFile("datas/shader/wave.sfx")) return EXIT_FAILURE; if (!shaders["pixelate"].LoadFromFile("datas/shader/pixelate.sfx")) return EXIT_FAILURE; ShaderSelector backgroundShader(shaders, "nothing"); ShaderSelector entityShader(shaders, "nothing"); ShaderSelector globalShader(shaders, "nothing"); // Do specific initializations shaders["nothing"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["blur"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["blur"].SetParameter("offset", 0.f); shaders["colorize"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["colorize"].SetParameter("color", 1.f, 1.f, 1.f); shaders["edge"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["fisheye"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["wave"].SetTexture("texture", sf::Shader::CurrentTexture); shaders["wave"].SetTexture("wave", waveImage); shaders["pixelate"].SetTexture("texture", sf::Shader::CurrentTexture); // Define a string for displaying the description of the current shader sf::Text shaderStr; shaderStr.SetFont(font); shaderStr.SetSize(20); shaderStr.SetPosition(5.f, 0.f); shaderStr.SetColor(sf::Color(250, 100, 30)); shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n" "Flower shader: \"" + entityShader.GetName() + "\"\n" "Global shader: \"" + globalShader.GetName() + "\"\n"); // Define a string for displaying help sf::Text infoStr; infoStr.SetFont(font); infoStr.SetSize(20); infoStr.SetPosition(5.f, 510.f); infoStr.SetColor(sf::Color(250, 100, 30)); infoStr.SetString("Move your mouse to change the shaders' parameters\n" "Press numpad 1/4 to change the background shader\n" "Press numpad 2/5 to change the flower shader\n" "Press numpad 3/6 to change the global shader"); // Create a clock to measure the total time elapsed sf::Clock clock; // Start the game loop while (window.IsOpened()) { // Process events sf::Event event; while (window.GetEvent(event)) { // Close window : exit if (event.Type == sf::Event::Closed) window.Close(); if (event.Type == sf::Event::KeyPressed) { // Escape key : exit if (event.Key.Code == sf::Key::Escape) window.Close(); // Numpad : switch effect switch (event.Key.Code) { case sf::Key::Numpad1 : backgroundShader.GotoPrevious(); break; case sf::Key::Numpad4 : backgroundShader.GotoNext(); break; case sf::Key::Numpad2 : entityShader.GotoPrevious(); break; case sf::Key::Numpad5 : entityShader.GotoNext(); break; case sf::Key::Numpad3 : globalShader.GotoPrevious(); break; case sf::Key::Numpad6 : globalShader.GotoNext(); break; default : break; } // Update the text shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n" "Entity shader: \"" + entityShader.GetName() + "\"\n" "Global shader: \"" + globalShader.GetName() + "\"\n"); } } // Get the mouse position in the range [0, 1] float mouseX = window.GetInput().GetMouseX() / static_cast(window.GetWidth()); float mouseY = window.GetInput().GetMouseY() / static_cast(window.GetHeight()); // Update the shaders backgroundShader.Update(mouseX, mouseY); entityShader.Update(mouseX, mouseY); globalShader.Update(mouseX, mouseY); // Animate the entity float entityX = (cos(clock.GetElapsedTime() * 1.3f) + 1.2f) * 300; float entityY = (cos(clock.GetElapsedTime() * 0.8f) + 1.2f) * 200; entity.SetPosition(entityX, entityY); entity.Rotate(window.GetFrameTime() * 100); // Draw the background and the moving entity to the render image image.Clear(); image.Draw(background, backgroundShader.GetShader()); image.Draw(entity, entityShader.GetShader()); image.Display(); // Draw the contents of the render image to the window sf::Sprite screen(image.GetImage()); window.Draw(screen, globalShader.GetShader()); // Draw the interface texts window.Draw(shaderStr); window.Draw(infoStr); // Finally, display the rendered frame on screen window.Display(); } return EXIT_SUCCESS; } //////////////////////////////////////////////////////////// /// Fonction called when the post-effects are not supported ; /// Display an error message and wait until the user exits /// //////////////////////////////////////////////////////////// void DisplayError() { // Create the main window sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Shader"); // Define a string for displaying the error message sf::Text error("Sorry, your system doesn't support shaders"); error.SetPosition(100.f, 250.f); error.SetColor(sf::Color(200, 100, 150)); // Start the game loop while (window.IsOpened()) { // Process events sf::Event event; while (window.GetEvent(event)) { // Close window : exit if (event.Type == sf::Event::Closed) window.Close(); // Escape key : exit if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Escape)) window.Close(); } // Clear the window window.Clear(); // Draw the error message window.Draw(error); // Finally, display the rendered frame on screen window.Display(); } }