diff --git a/examples/opengl/OpenGL.cpp b/examples/opengl/OpenGL.cpp index fd00839d..f86522ee 100644 --- a/examples/opengl/OpenGL.cpp +++ b/examples/opengl/OpenGL.cpp @@ -4,7 +4,6 @@ //////////////////////////////////////////////////////////// #include #include -#include //////////////////////////////////////////////////////////// /// Entry point of application @@ -77,9 +76,9 @@ int main() } // Draw the background - window.SaveGLStates(); + window.PushGLStates(); window.Draw(background); - window.RestoreGLStates(); + window.PopGLStates(); // Activate the window before using OpenGL commands. // This is useless here because we have only one window which is @@ -138,12 +137,12 @@ int main() glEnd(); // Draw some text on top of our OpenGL object - window.SaveGLStates(); + window.PushGLStates(); sf::Text text("SFML / OpenGL demo"); - text.SetPosition(250.f, 450.f); text.SetColor(sf::Color(255, 255, 255, 170)); + text.SetPosition(250.f, 450.f); window.Draw(text); - window.RestoreGLStates(); + window.PopGLStates(); // Finally, display the rendered frame on screen window.Display(); diff --git a/examples/pong/Pong.cpp b/examples/pong/Pong.cpp index 0e9abfc4..a203dea7 100644 --- a/examples/pong/Pong.cpp +++ b/examples/pong/Pong.cpp @@ -19,172 +19,216 @@ int main() { std::srand(static_cast(std::time(NULL))); - // Defines PI - const float PI = 3.14159f; + // Define some constants + const float pi = 3.14159f; + const int gameWidth = 800; + const int gameHeight = 600; + sf::Vector2f paddleSize(25, 100); + float ballRadius = 10.f; // Create the window of the application - sf::RenderWindow window(sf::VideoMode(800, 600, 32), "SFML Pong"); + sf::RenderWindow window(sf::VideoMode(gameWidth, gameHeight, 32), "SFML Pong"); // Load the sounds used in the game sf::SoundBuffer ballSoundBuffer; if (!ballSoundBuffer.LoadFromFile("resources/ball.wav")) - { return EXIT_FAILURE; - } sf::Sound ballSound(ballSoundBuffer); - // Load the textures used in the game - sf::Texture backgroundTexture, leftPaddleTexture, rightPaddleTexture, ballTexture; - if (!backgroundTexture.LoadFromFile("resources/background.jpg") || - !leftPaddleTexture.LoadFromFile("resources/paddle_left.png") || - !rightPaddleTexture.LoadFromFile("resources/paddle_right.png") || - !ballTexture.LoadFromFile("resources/ball.png")) - { - return EXIT_FAILURE; - } + // Create the left paddle + sf::RectangleShape leftPaddle; + leftPaddle.SetSize(paddleSize - sf::Vector2f(3, 3)); + leftPaddle.SetOutlineThickness(3); + leftPaddle.SetOutlineColor(sf::Color::Black); + leftPaddle.SetFillColor(sf::Color(100, 100, 200)); + leftPaddle.SetOrigin(paddleSize / 2.f); + + // Create the right paddle + sf::RectangleShape rightPaddle; + rightPaddle.SetSize(paddleSize - sf::Vector2f(3, 3)); + rightPaddle.SetOutlineThickness(3); + rightPaddle.SetOutlineColor(sf::Color::Black); + rightPaddle.SetFillColor(sf::Color(200, 100, 100)); + rightPaddle.SetOrigin(paddleSize / 2.f); + + // Create the ball + sf::CircleShape ball; + ball.SetRadius(ballRadius - 3); + ball.SetOutlineThickness(3); + ball.SetOutlineColor(sf::Color::Black); + ball.SetFillColor(sf::Color::White); + ball.SetOrigin(ballRadius / 2, ballRadius / 2); // Load the text font sf::Font font; if (!font.LoadFromFile("resources/sansation.ttf")) return EXIT_FAILURE; - // Initialize the end text - sf::Text end; - end.SetFont(font); - end.SetCharacterSize(60); - end.Move(150.f, 200.f); - end.SetColor(sf::Color(50, 50, 250)); - - // Create the sprites of the background, the paddles and the ball - sf::Sprite background(backgroundTexture); - sf::Sprite leftPaddle(leftPaddleTexture); - sf::Sprite rightPaddle(rightPaddleTexture); - sf::Sprite ball(ballTexture); - - leftPaddle.Move(10, (window.GetView().GetSize().y - leftPaddle.GetSize().y) / 2); - rightPaddle.Move(window.GetView().GetSize().x - rightPaddle.GetSize().x - 10, (window.GetView().GetSize().y - rightPaddle.GetSize().y) / 2); - ball.Move((window.GetView().GetSize().x - ball.GetSize().x) / 2, (window.GetView().GetSize().y - ball.GetSize().y) / 2); + // Initialize the pause message + sf::Text pauseMessage; + pauseMessage.SetFont(font); + pauseMessage.SetCharacterSize(40); + pauseMessage.SetPosition(170.f, 150.f); + pauseMessage.SetColor(sf::Color::White); + pauseMessage.SetString("Welcome to SFML pong!\nPress space to start the game"); // Define the paddles properties sf::Clock AITimer; - const float AITime = 0.1f; - float leftPaddleSpeed = 400.f; - float rightPaddleSpeed = 400.f; + const sf::Uint32 AITime = 300; + const float paddleSpeed = 400.f; + float rightPaddleSpeed = 0.f; + const float ballSpeed = 400.f; + float ballAngle = 0.f; // to be changed later - // Define the ball properties - float ballSpeed = 400.f; - float ballAngle; - do - { - // Make sure the ball initial angle is not too much vertical - ballAngle = std::rand() * 2 * PI / RAND_MAX; - } while (std::abs(std::cos(ballAngle)) < 0.7f); - - bool isPlaying = true; + bool isPlaying = false; while (window.IsOpened()) { // Handle events sf::Event event; while (window.PollEvent(event)) { - // Window closed or escape key pressed : exit + // Window closed or escape key pressed: exit if ((event.Type == sf::Event::Closed) || ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Keyboard::Escape))) { window.Close(); break; } + + // Space key pressed: play + if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Keyboard::Space)) + { + if (!isPlaying) + { + // (re)start the game + isPlaying = true; + + // Reset the position of the paddles and ball + leftPaddle.SetPosition(10 + paddleSize.x / 2, gameHeight / 2); + rightPaddle.SetPosition(gameWidth - 10 - paddleSize.x / 2, gameHeight / 2); + ball.SetPosition(gameWidth / 2, gameHeight / 2); + + // Reset the ball angle + do + { + // Make sure the ball initial angle is not too much vertical + ballAngle = (std::rand() % 360) * 2 * pi / 360; + } + while (std::abs(std::cos(ballAngle)) < 0.7f); + } + } } if (isPlaying) { + float deltaTime = window.GetFrameTime() / 1000.f; + // Move the player's paddle - if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Up) && (leftPaddle.GetPosition().y > 5.f)) - leftPaddle.Move(0.f, -leftPaddleSpeed * window.GetFrameTime() / 1000.f); - if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Down) && (leftPaddle.GetPosition().y < window.GetView().GetSize().y - leftPaddle.GetSize().y - 5.f)) - leftPaddle.Move(0.f, leftPaddleSpeed * window.GetFrameTime() / 1000.f); + if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Up) && + (leftPaddle.GetPosition().y - paddleSize.y / 2 > 5.f)) + { + leftPaddle.Move(0.f, -paddleSpeed * deltaTime); + } + if (sf::Keyboard::IsKeyPressed(sf::Keyboard::Down) && + (leftPaddle.GetPosition().y + paddleSize.y / 2 < gameHeight - 5.f)) + { + leftPaddle.Move(0.f, paddleSpeed * deltaTime); + } // Move the computer's paddle - if (((rightPaddleSpeed < 0.f) && (rightPaddle.GetPosition().y > 5.f)) || - ((rightPaddleSpeed > 0.f) && (rightPaddle.GetPosition().y < window.GetView().GetSize().y - rightPaddle.GetSize().y - 5.f))) + if (((rightPaddleSpeed < 0.f) && (rightPaddle.GetPosition().y - paddleSize.y / 2 > 5.f)) || + ((rightPaddleSpeed > 0.f) && (rightPaddle.GetPosition().y + paddleSize.y / 2 < gameHeight - 5.f))) { - rightPaddle.Move(0.f, rightPaddleSpeed * window.GetFrameTime() / 1000.f); + rightPaddle.Move(0.f, rightPaddleSpeed * deltaTime); } // Update the computer's paddle direction according to the ball position if (AITimer.GetElapsedTime() > AITime) { AITimer.Reset(); - if ((rightPaddleSpeed < 0) && (ball.GetPosition().y + ball.GetSize().y > rightPaddle.GetPosition().y + rightPaddle.GetSize().y)) - rightPaddleSpeed = -rightPaddleSpeed; - if ((rightPaddleSpeed > 0) && (ball.GetPosition().y < rightPaddle.GetPosition().y)) - rightPaddleSpeed = -rightPaddleSpeed; + if (ball.GetPosition().y + ballRadius > rightPaddle.GetPosition().y + paddleSize.y / 2) + rightPaddleSpeed = paddleSpeed; + else if (ball.GetPosition().y - ballRadius < rightPaddle.GetPosition().y - paddleSize.y / 2) + rightPaddleSpeed = -paddleSpeed; + else + rightPaddleSpeed = 0.f; } // Move the ball - float factor = ballSpeed * window.GetFrameTime() / 1000.f; - ball.Move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor); + float factor = ballSpeed * deltaTime; + ball.Move(std::cos(ballAngle) * factor, std::sin(ballAngle) * factor); // Check collisions between the ball and the screen - if (ball.GetPosition().x < 0.f) + if (ball.GetPosition().x - ballRadius < 0.f) { isPlaying = false; - end.SetString("You lost !\n(press escape to exit)"); + pauseMessage.SetString("You lost !\nPress space to restart or\nescape to exit"); } - if (ball.GetPosition().x + ball.GetSize().x > window.GetView().GetSize().x) + if (ball.GetPosition().x + ballRadius > 800) { isPlaying = false; - end.SetString("You won !\n(press escape to exit)"); + pauseMessage.SetString("You won !\nPress space to restart or\nescape to exit"); } - if (ball.GetPosition().y < 0.f) + if (ball.GetPosition().y - ballRadius < 0.f) { ballSound.Play(); ballAngle = -ballAngle; - ball.SetY(0.1f); + ball.SetPosition(ball.GetPosition().x, ballRadius + 0.1f); } - if (ball.GetPosition().y + ball.GetSize().y > window.GetView().GetSize().y) + if (ball.GetPosition().y + ballRadius > gameHeight) { ballSound.Play(); ballAngle = -ballAngle; - ball.SetY(window.GetView().GetSize().y - ball.GetSize().y - 0.1f); + ball.SetPosition(ball.GetPosition().x, gameHeight - ballRadius - 0.1f); } // Check the collisions between the ball and the paddles // Left Paddle - if (ball.GetPosition().x < leftPaddle.GetPosition().x + leftPaddle.GetSize().x && - ball.GetPosition().x > leftPaddle.GetPosition().x + (leftPaddle.GetSize().x / 2.0f) && - ball.GetPosition().y + ball.GetSize().y >= leftPaddle.GetPosition().y && - ball.GetPosition().y <= leftPaddle.GetPosition().y + leftPaddle.GetSize().y) + if (ball.GetPosition().x - ballRadius < leftPaddle.GetPosition().x + paddleSize.x / 2 && + ball.GetPosition().x - ballRadius > leftPaddle.GetPosition().x && + ball.GetPosition().y + ballRadius >= leftPaddle.GetPosition().y - paddleSize.y / 2 && + ball.GetPosition().y - ballRadius <= leftPaddle.GetPosition().y + paddleSize.y / 2) { + if (ball.GetPosition().y > leftPaddle.GetPosition().y) + ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180; + else + ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180; + ballSound.Play(); - ballAngle = PI - ballAngle; - ball.SetX(leftPaddle.GetPosition().x + leftPaddle.GetSize().x + 0.1f); + ball.SetPosition(leftPaddle.GetPosition().x + ballRadius + paddleSize.x / 2 + 0.1f, ball.GetPosition().y); } // Right Paddle - if (ball.GetPosition().x + ball.GetSize().x > rightPaddle.GetPosition().x && - ball.GetPosition().x + ball.GetSize().x < rightPaddle.GetPosition().x + (rightPaddle.GetSize().x / 2.0f) && - ball.GetPosition().y + ball.GetSize().y >= rightPaddle.GetPosition().y && - ball.GetPosition().y <= rightPaddle.GetPosition().y + rightPaddle.GetSize().y) + if (ball.GetPosition().x + ballRadius > rightPaddle.GetPosition().x - paddleSize.x / 2 && + ball.GetPosition().x + ballRadius < rightPaddle.GetPosition().x && + ball.GetPosition().y + ballRadius >= rightPaddle.GetPosition().y - paddleSize.y / 2 && + ball.GetPosition().y - ballRadius <= rightPaddle.GetPosition().y + paddleSize.y / 2) { + if (ball.GetPosition().y > rightPaddle.GetPosition().y) + ballAngle = pi - ballAngle + (std::rand() % 20) * pi / 180; + else + ballAngle = pi - ballAngle - (std::rand() % 20) * pi / 180; + ballSound.Play(); - ballAngle = PI - ballAngle; - ball.SetX(rightPaddle.GetPosition().x - ball.GetSize().x - 0.1f); + ball.SetPosition(rightPaddle.GetPosition().x - ballRadius - paddleSize.x / 2 - 0.1f, ball.GetPosition().y); } } // Clear the window - window.Clear(); + window.Clear(sf::Color(50, 200, 50)); - // Draw the background, paddles and ball sprites - window.Draw(background); - window.Draw(leftPaddle); - window.Draw(rightPaddle); - window.Draw(ball); - - // If the game is over, display the end message - if (!isPlaying) - window.Draw(end); + if (isPlaying) + { + // Draw the paddles and the ball + window.Draw(leftPaddle); + window.Draw(rightPaddle); + window.Draw(ball); + } + else + { + // Draw the pause message + window.Draw(pauseMessage); + } // Display things on screen window.Display(); diff --git a/examples/pong/resources/background.jpg b/examples/pong/resources/background.jpg deleted file mode 100644 index 06dfdb8b..00000000 Binary files a/examples/pong/resources/background.jpg and /dev/null differ diff --git a/examples/pong/resources/ball.png b/examples/pong/resources/ball.png deleted file mode 100644 index c296859b..00000000 Binary files a/examples/pong/resources/ball.png and /dev/null differ diff --git a/examples/pong/resources/paddle_left.png b/examples/pong/resources/paddle_left.png deleted file mode 100644 index 63592c9b..00000000 Binary files a/examples/pong/resources/paddle_left.png and /dev/null differ diff --git a/examples/pong/resources/paddle_right.png b/examples/pong/resources/paddle_right.png deleted file mode 100644 index d408c5fd..00000000 Binary files a/examples/pong/resources/paddle_right.png and /dev/null differ diff --git a/examples/shader/CMakeLists.txt b/examples/shader/CMakeLists.txt index 5b610d4d..acb1bac8 100644 --- a/examples/shader/CMakeLists.txt +++ b/examples/shader/CMakeLists.txt @@ -2,7 +2,9 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/examples/shader) # all source files -set(SRC ${SRCROOT}/Shader.cpp) +set(SRC + ${SRCROOT}/Effect.hpp + ${SRCROOT}/Shader.cpp) # define the shader target sfml_add_example(shader GUI_APP diff --git a/examples/shader/Effect.hpp b/examples/shader/Effect.hpp new file mode 100644 index 00000000..cb5b3668 --- /dev/null +++ b/examples/shader/Effect.hpp @@ -0,0 +1,74 @@ +#ifndef EFFECT_HPP +#define EFFECT_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +//////////////////////////////////////////////////////////// +// Base class for effects +//////////////////////////////////////////////////////////// +class Effect : public sf::Drawable +{ +public : + + virtual ~Effect() + { + } + + const std::string& GetName() const + { + return myName; + } + + void Load() + { + myIsLoaded = sf::Shader::IsAvailable() && OnLoad(); + } + + void Update(float time, float x, float y) + { + if (myIsLoaded) + OnUpdate(time, x, y); + } + + void Draw(sf::RenderTarget& target, sf::RenderStates states) const + { + if (myIsLoaded) + { + OnDraw(target, states); + } + else + { + sf::Text error("Shader not\nsupported"); + error.SetPosition(320.f, 200.f); + error.SetCharacterSize(36); + target.Draw(error, states); + } + } + +protected : + + Effect(const std::string& name) : + myName(name), + myIsLoaded(false) + { + } + +private : + + // Virtual functions to be implemented in derived effects + virtual bool OnLoad() = 0; + virtual void OnUpdate(float time, float x, float y) = 0; + virtual void OnDraw(sf::RenderTarget& target, sf::RenderStates states) const = 0; + +private : + + std::string myName; + bool myIsLoaded; +}; + +#endif // EFFECT_HPP diff --git a/examples/shader/Shader.cpp b/examples/shader/Shader.cpp index 40ca7324..4451c301 100644 --- a/examples/shader/Shader.cpp +++ b/examples/shader/Shader.cpp @@ -2,71 +2,257 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// +#include "Effect.hpp" #include -#include +#include #include -void DisplayError(); - //////////////////////////////////////////////////////////// -/// A class to simplify shader selection -/// +// "Pixelate" fragment shader //////////////////////////////////////////////////////////// -class ShaderSelector +class Pixelate : public Effect { public : - // Constructor - ShaderSelector(std::map& owner, const std::string& shader) : - myOwner (&owner), - myIterator(owner.find(shader)) + Pixelate() : + Effect("pixelate") { } - // Select the previous shader - void GotoPrevious() + bool OnLoad() { - if (myIterator == myOwner->begin()) - myIterator = myOwner->end(); - myIterator--; + // Load the texture and initialize the sprite + if (!myTexture.LoadFromFile("resources/background.jpg")) + return false; + mySprite.SetTexture(myTexture); + + // Load the shader + if (!myShader.LoadFromFile("resources/pixelate.frag", sf::Shader::Fragment)) + return false; + myShader.SetParameter("texture", sf::Shader::CurrentTexture); + + return true; } - // Select the next shader - void GotoNext() + void OnUpdate(float, float x, float y) { - myIterator++; - if (myIterator == myOwner->end()) - myIterator = myOwner->begin(); + myShader.SetParameter("pixel_threshold", (x + y) / 30); } - // Update the shader parameters - void Update(float x, float y) + void OnDraw(sf::RenderTarget& target, sf::RenderStates states) const { - 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); + states.Shader = &myShader; + target.Draw(mySprite, states); } - // Get the name of the current shader - const std::string& GetName() const +private: + + sf::Texture myTexture; + sf::Sprite mySprite; + sf::Shader myShader; +}; + + +//////////////////////////////////////////////////////////// +// "Wave" vertex shader + "blur" fragment shader +//////////////////////////////////////////////////////////// +class WaveBlur : public Effect +{ +public : + + WaveBlur() : + Effect("wave + blur") { - return myIterator->first; } - // Get the current shader - const sf::Shader& GetShader() const + bool OnLoad() { - return myIterator->second; + // Create the text + myText.SetString("Praesent suscipit augue in velit pulvinar hendrerit varius purus aliquam.\n" + "Mauris mi odio, bibendum quis fringilla a, laoreet vel orci. Proin vitae vulputate tortor.\n" + "Praesent cursus ultrices justo, ut feugiat ante vehicula quis.\n" + "Donec fringilla scelerisque mauris et viverra.\n" + "Maecenas adipiscing ornare scelerisque. Nullam at libero elit.\n" + "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n" + "Nullam leo urna, tincidunt id semper eget, ultricies sed mi.\n" + "Morbi mauris massa, commodo id dignissim vel, lobortis et elit.\n" + "Fusce vel libero sed neque scelerisque venenatis.\n" + "Integer mattis tincidunt quam vitae iaculis.\n" + "Vivamus fringilla sem non velit venenatis fermentum.\n" + "Vivamus varius tincidunt nisi id vehicula.\n" + "Integer ullamcorper, enim vitae euismod rutrum, massa nisl semper ipsum,\n" + "vestibulum sodales sem ante in massa.\n" + "Vestibulum in augue non felis convallis viverra.\n" + "Mauris ultricies dolor sed massa convallis sed aliquet augue fringilla.\n" + "Duis erat eros, porta in accumsan in, blandit quis sem.\n" + "In hac habitasse platea dictumst. Etiam fringilla est id odio dapibus sit amet semper dui laoreet.\n"); + myText.SetCharacterSize(22); + myText.SetPosition(30, 20); + + // Load the shader + //if (!myShader.LoadFromFile("resources/wave.vert", sf::Shader::Vertex)) + if (!myShader.LoadFromFile("resources/wave.vert", "resources/blur.frag")) + return false; + + return true; } -private : + void OnUpdate(float time, float x, float y) + { + myShader.SetParameter("wave_phase", time); + myShader.SetParameter("wave_amplitude", x * 40, y * 40); + myShader.SetParameter("blur_radius", (x + y) * 0.008f); + } - std::map* myOwner; - std::map::iterator myIterator; + void OnDraw(sf::RenderTarget& target, sf::RenderStates states) const + { + states.Shader = &myShader; + target.Draw(myText, states); + } + +private: + + sf::Text myText; + sf::Shader myShader; +}; + + +//////////////////////////////////////////////////////////// +// "Storm" vertex shader + "blink" fragment shader +//////////////////////////////////////////////////////////// +class StormBlink : public Effect +{ +public : + + StormBlink() : + Effect("storm + blink") + { + } + + bool OnLoad() + { + // Create the points + myPoints.SetPrimitiveType(sf::Points); + for (int i = 0; i < 40000; ++i) + { + float x = static_cast(std::rand() % 800); + float y = static_cast(std::rand() % 600); + sf::Uint8 r = std::rand() % 255; + sf::Uint8 g = std::rand() % 255; + sf::Uint8 b = std::rand() % 255; + myPoints.Append(sf::Vertex(sf::Vector2f(x, y), sf::Color(r, g, b))); + } + + // Load the shader + if (!myShader.LoadFromFile("resources/storm.vert", "resources/blink.frag")) + return false; + + return true; + } + + void OnUpdate(float time, float x, float y) + { + float radius = 200 + std::cos(time) * 150; + myShader.SetParameter("storm_position", x * 800, y * 600); + myShader.SetParameter("storm_inner_radius", radius / 3); + myShader.SetParameter("storm_total_radius", radius); + myShader.SetParameter("blink_alpha", 0.5f + std::cos(time * 3) * 0.25f); + } + + void OnDraw(sf::RenderTarget& target, sf::RenderStates states) const + { + states.Shader = &myShader; + target.Draw(myPoints, states); + } + +private: + + sf::VertexArray myPoints; + sf::Shader myShader; +}; + + +//////////////////////////////////////////////////////////// +// "Edge" post-effect fragment shader +//////////////////////////////////////////////////////////// +class Edge : public Effect +{ +public : + + Edge() : + Effect("edge post-effect") + { + } + + bool OnLoad() + { + // Create the off-screen surface + if (!mySurface.Create(800, 600)) + return false; + mySurface.SetSmooth(true); + + // Load the textures + if (!myBackgroundTexture.LoadFromFile("resources/sfml.png")) + return false; + myBackgroundTexture.SetSmooth(true); + if (!myEntityTexture.LoadFromFile("resources/devices.png")) + return false; + myEntityTexture.SetSmooth(true); + + // Initialize the background sprite + myBackgroundSprite.SetTexture(myBackgroundTexture); + myBackgroundSprite.SetPosition(135, 100); + + // Load the moving entities + for (int i = 0; i < 6; ++i) + { + sf::Sprite entity(myEntityTexture, sf::IntRect(96 * i, 0, 96, 96)); + myEntities.push_back(entity); + } + + // Load the shader + if (!myShader.LoadFromFile("resources/edge.frag", sf::Shader::Fragment)) + return false; + myShader.SetParameter("texture", sf::Shader::CurrentTexture); + + return true; + } + + void OnUpdate(float time, float x, float y) + { + myShader.SetParameter("edge_threshold", 1 - (x + y) / 2); + + // Update the position of the moving entities + for (std::size_t i = 0; i < myEntities.size(); ++i) + { + float x = std::cos(0.25f * (time * i + (myEntities.size() - i))) * 300 + 350; + float y = std::sin(0.25f * (time * (myEntities.size() - i) + i)) * 200 + 250; + myEntities[i].SetPosition(x, y); + } + + // Render the updated scene to the off-screen surface + mySurface.Clear(sf::Color::White); + mySurface.Draw(myBackgroundSprite); + for (std::size_t i = 0; i < myEntities.size(); ++i) + mySurface.Draw(myEntities[i]); + mySurface.Display(); + } + + void OnDraw(sf::RenderTarget& target, sf::RenderStates states) const + { + states.Shader = &myShader; + target.Draw(sf::Sprite(mySurface.GetTexture()), states); + } + +private: + + sf::RenderTexture mySurface; + sf::Texture myBackgroundTexture; + sf::Texture myEntityTexture; + sf::Sprite myBackgroundSprite; + std::vector myEntities; + sf::Shader myShader; }; @@ -78,203 +264,110 @@ private : //////////////////////////////////////////////////////////// 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"); + window.EnableVerticalSync(true); - // Create the render texture - sf::RenderTexture texture; - if (!texture.Create(window.GetWidth(), window.GetHeight())) + // Create the effects + std::vector effects; + effects.push_back(new Pixelate); + effects.push_back(new WaveBlur); + effects.push_back(new StormBlink); + effects.push_back(new Edge); + std::size_t current = 0; + + // Initialize them + for (std::size_t i = 0; i < effects.size(); ++i) + effects[i]->Load(); + + // Create the messages background + sf::Texture textBackgroundTexture; + if (!textBackgroundTexture.LoadFromFile("resources/text-background.png")) return EXIT_FAILURE; + sf::Sprite textBackground(textBackgroundTexture); + textBackground.SetPosition(0, 520); + textBackground.SetColor(sf::Color(255, 255, 255, 200)); - // Load a background texture to display - sf::Texture backgroundTexture; - if (!backgroundTexture.LoadFromFile("resources/background.jpg")) - return EXIT_FAILURE; - sf::Sprite background(backgroundTexture); - - // Load a sprite which we'll move into the scene - sf::Texture entityTexture; - if (!entityTexture.LoadFromFile("resources/sprite.png")) - return EXIT_FAILURE; - sf::Sprite entity(entityTexture); - - // Load the text font + // Load the messages font sf::Font font; if (!font.LoadFromFile("resources/sansation.ttf")) return EXIT_FAILURE; - // Load the texture needed for the wave shader - sf::Texture waveTexture; - if (!waveTexture.LoadFromFile("resources/wave.jpg")) - return EXIT_FAILURE; + // Create the description text + sf::Text description("Current effect: " + effects[current]->GetName(), font, 20); + description.SetPosition(10, 530); + description.SetColor(sf::Color(80, 80, 80)); - // Load all shaders - std::map shaders; - if (!shaders["nothing"].LoadFromFile("resources/nothing.sfx")) return EXIT_FAILURE; - if (!shaders["blur"].LoadFromFile("resources/blur.sfx")) return EXIT_FAILURE; - if (!shaders["colorize"].LoadFromFile("resources/colorize.sfx")) return EXIT_FAILURE; - if (!shaders["edge"].LoadFromFile("resources/edge.sfx")) return EXIT_FAILURE; - if (!shaders["fisheye"].LoadFromFile("resources/fisheye.sfx")) return EXIT_FAILURE; - if (!shaders["wave"].LoadFromFile("resources/wave.sfx")) return EXIT_FAILURE; - if (!shaders["pixelate"].LoadFromFile("resources/pixelate.sfx")) return EXIT_FAILURE; - ShaderSelector backgroundShader(shaders, "nothing"); - ShaderSelector entityShader(shaders, "nothing"); - ShaderSelector globalShader(shaders, "nothing"); - - // Do specific initializations - shaders["nothing"].SetCurrentTexture("texture"); - shaders["blur"].SetCurrentTexture("texture"); - shaders["blur"].SetParameter("offset", 0.f); - shaders["colorize"].SetCurrentTexture("texture"); - shaders["colorize"].SetParameter("color", 1.f, 1.f, 1.f); - shaders["edge"].SetCurrentTexture("texture"); - shaders["fisheye"].SetCurrentTexture("texture"); - shaders["wave"].SetCurrentTexture("texture"); - shaders["wave"].SetTexture("wave", waveTexture); - shaders["pixelate"].SetCurrentTexture("texture"); - - // Define a string for displaying the description of the current shader - sf::Text shaderStr; - shaderStr.SetFont(font); - shaderStr.SetCharacterSize(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.SetCharacterSize(20); - infoStr.SetPosition(5.f, 500.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; + // Create the instructions text + sf::Text instructions("Press left and right arrows to change the current shader", font, 20); + instructions.SetPosition(280, 555); + instructions.SetColor(sf::Color(80, 80, 80)); // Start the game loop + sf::Clock clock; while (window.IsOpened()) { // Process events sf::Event event; while (window.PollEvent(event)) { - // Close window : exit + // 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::Keyboard::Escape) - window.Close(); - - // Numpad : switch effect switch (event.Key.Code) { - case sf::Keyboard::Numpad1 : backgroundShader.GotoPrevious(); break; - case sf::Keyboard::Numpad4 : backgroundShader.GotoNext(); break; - case sf::Keyboard::Numpad2 : entityShader.GotoPrevious(); break; - case sf::Keyboard::Numpad5 : entityShader.GotoNext(); break; - case sf::Keyboard::Numpad3 : globalShader.GotoPrevious(); break; - case sf::Keyboard::Numpad6 : globalShader.GotoNext(); break; - default : break; - } + // Escape key: exit + case sf::Keyboard::Escape: + window.Close(); + break; - // Update the text - shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n" - "Entity shader: \"" + entityShader.GetName() + "\"\n" - "Global shader: \"" + globalShader.GetName() + "\"\n"); + // Left arrow key: previous shader + case sf::Keyboard::Left: + if (current == 0) + current = effects.size() - 1; + else + current--; + description.SetString("Current effect: " + effects[current]->GetName()); + break; + + // Right arrow key: next shader + case sf::Keyboard::Right: + if (current == effects.size() - 1) + current = 0; + else + current++; + description.SetString("Current effect: " + effects[current]->GetName()); + break; + } } } - // Get the mouse position in the range [0, 1] - float mouseX = sf::Mouse::GetPosition(window).x / static_cast(window.GetWidth()); - float mouseY = sf::Mouse::GetPosition(window).y / static_cast(window.GetHeight()); + // Update the current example + float x = static_cast(sf::Mouse::GetPosition(window).x) / window.GetWidth(); + float y = static_cast(sf::Mouse::GetPosition(window).y) / window.GetHeight(); + effects[current]->Update(clock.GetElapsedTime() / 1000.f, x, y); - // Update the shaders - backgroundShader.Update(mouseX, mouseY); - entityShader.Update(mouseX, mouseY); - globalShader.Update(mouseX, mouseY); + // Clear the window + window.Clear(sf::Color(255, 128, 0)); - // Animate the entity - float entityX = (std::cos(clock.GetElapsedTime() * 0.0013f) + 1.2f) * 300; - float entityY = (std::cos(clock.GetElapsedTime() * 0.0008f) + 1.2f) * 200; - entity.SetPosition(entityX, entityY); - entity.Rotate(window.GetFrameTime() * 0.1f); + // Draw the current example + window.Draw(*effects[current]); - // Draw the background and the moving entity to the render texture - texture.Clear(); - texture.Draw(background, backgroundShader.GetShader()); - texture.Draw(entity, entityShader.GetShader()); - texture.Display(); - - // Draw the contents of the render texture to the window - sf::Sprite screen(texture.GetTexture()); - window.Draw(screen, globalShader.GetShader()); - - // Draw the interface texts - window.Draw(shaderStr); - window.Draw(infoStr); + // Draw the text + window.Draw(textBackground); + window.Draw(instructions); + window.Draw(description); // Finally, display the rendered frame on screen window.Display(); } + // delete the effects + for (std::size_t i = 0; i < effects.size(); ++i) + delete effects[i]; + 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.PollEvent(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::Keyboard::Escape)) - window.Close(); - } - - // Clear the window - window.Clear(); - - // Draw the error message - window.Draw(error); - - // Finally, display the rendered frame on screen - window.Display(); - } -} diff --git a/examples/shader/resources/blink.frag b/examples/shader/resources/blink.frag new file mode 100644 index 00000000..07c8ddb2 --- /dev/null +++ b/examples/shader/resources/blink.frag @@ -0,0 +1,9 @@ +uniform sampler2D texture; +uniform float blink_alpha; + +void main() +{ + vec4 pixel = gl_Color; + pixel.a = blink_alpha; + gl_FragColor = pixel; +} diff --git a/examples/shader/resources/blur.sfx b/examples/shader/resources/blur.frag similarity index 73% rename from examples/shader/resources/blur.sfx rename to examples/shader/resources/blur.frag index bde2fa65..c40e5b3f 100644 --- a/examples/shader/resources/blur.sfx +++ b/examples/shader/resources/blur.frag @@ -1,12 +1,12 @@ uniform sampler2D texture; -uniform float offset; +uniform float blur_radius; void main() { - vec2 offx = vec2(offset, 0.0); - vec2 offy = vec2(0.0, offset); + vec2 offx = vec2(blur_radius, 0.0); + vec2 offy = vec2(0.0, blur_radius); - vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 1.0 + + vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 + texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 + texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 + texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 + @@ -16,5 +16,5 @@ void main() texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 + texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0; - gl_FragColor = gl_Color * (pixel / 13.0); + gl_FragColor = gl_Color * (pixel / 16.0); } diff --git a/examples/shader/resources/colorize.sfx b/examples/shader/resources/colorize.sfx deleted file mode 100644 index eeb407c8..00000000 --- a/examples/shader/resources/colorize.sfx +++ /dev/null @@ -1,11 +0,0 @@ -uniform sampler2D texture; -uniform vec3 color; - -void main() -{ - vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * gl_Color; - float gray = pixel.r * 0.39 + pixel.g * 0.50 + pixel.b * 0.11; - - gl_FragColor = vec4(gray * color, 1.0) * 0.6 + pixel * 0.4; - gl_FragColor.a = pixel.a; -} diff --git a/examples/shader/resources/devices.png b/examples/shader/resources/devices.png new file mode 100644 index 00000000..6b1cbc85 Binary files /dev/null and b/examples/shader/resources/devices.png differ diff --git a/examples/shader/resources/edge.sfx b/examples/shader/resources/edge.frag similarity index 81% rename from examples/shader/resources/edge.sfx rename to examples/shader/resources/edge.frag index d944c583..14551f98 100644 --- a/examples/shader/resources/edge.sfx +++ b/examples/shader/resources/edge.frag @@ -1,5 +1,5 @@ uniform sampler2D texture; -uniform float threshold; +uniform float edge_threshold; void main() { @@ -23,9 +23,10 @@ void main() vec3 result = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb); float edge = length(result); - if (edge > threshold) - gl_FragColor.rgb = vec3(0, 0, 0); + vec4 pixel = gl_Color * texture2D(texture, gl_TexCoord[0].xy); + if (edge > (edge_threshold * 8.0)) + pixel.rgb = vec3(0.0, 0.0, 0.0); else - gl_FragColor.rgb = vec3(1, 1, 1); - gl_FragColor.a = gl_Color.a * texture2D(texture, gl_TexCoord[0].xy).a; + pixel.a = edge_threshold; + gl_FragColor = pixel; } diff --git a/examples/shader/resources/fisheye.sfx b/examples/shader/resources/fisheye.sfx deleted file mode 100644 index 97e3f8e4..00000000 --- a/examples/shader/resources/fisheye.sfx +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D texture; -uniform vec2 mouse; - -void main() -{ - float len = distance(gl_TexCoord[0].xy, mouse) * 7.0; - - vec2 coords = gl_TexCoord[0].xy; - if (len < 1.0) - coords += (gl_TexCoord[0].xy - mouse) * len; - - gl_FragColor = texture2D(texture, coords) * gl_Color; -} diff --git a/examples/shader/resources/nothing.sfx b/examples/shader/resources/nothing.sfx deleted file mode 100644 index cde0473a..00000000 --- a/examples/shader/resources/nothing.sfx +++ /dev/null @@ -1,6 +0,0 @@ -uniform sampler2D texture; - -void main() -{ - gl_FragColor = texture2D(texture, gl_TexCoord[0].xy) * gl_Color; -} diff --git a/examples/shader/resources/pixelate.sfx b/examples/shader/resources/pixelate.frag similarity index 63% rename from examples/shader/resources/pixelate.sfx rename to examples/shader/resources/pixelate.frag index 12a334e7..3c8eb0e0 100644 --- a/examples/shader/resources/pixelate.sfx +++ b/examples/shader/resources/pixelate.frag @@ -1,10 +1,9 @@ uniform sampler2D texture; -uniform vec2 mouse; +uniform float pixel_threshold; void main() { - float factor = 5.0 + 100.0 * length(mouse); + float factor = 1.0 / (pixel_threshold + 0.001); vec2 pos = floor(gl_TexCoord[0].xy * factor + 0.5) / factor; - gl_FragColor = texture2D(texture, pos) * gl_Color; } diff --git a/examples/shader/resources/sfml.png b/examples/shader/resources/sfml.png new file mode 100644 index 00000000..1da719ff Binary files /dev/null and b/examples/shader/resources/sfml.png differ diff --git a/examples/shader/resources/sprite.png b/examples/shader/resources/sprite.png deleted file mode 100644 index 7b508f68..00000000 Binary files a/examples/shader/resources/sprite.png and /dev/null differ diff --git a/examples/shader/resources/storm.vert b/examples/shader/resources/storm.vert new file mode 100644 index 00000000..442f80a9 --- /dev/null +++ b/examples/shader/resources/storm.vert @@ -0,0 +1,19 @@ +uniform vec2 storm_position; +uniform float storm_total_radius; +uniform float storm_inner_radius; + +void main() +{ + vec4 vertex = gl_ModelViewMatrix * gl_Vertex; + vec2 offset = vertex.xy - storm_position; + float len = length(offset); + if (len < storm_total_radius) + { + float push_distance = storm_inner_radius + len / storm_total_radius * (storm_total_radius - storm_inner_radius); + vertex.xy = storm_position + normalize(offset) * push_distance; + } + + gl_Position = gl_ProjectionMatrix * vertex; + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + gl_FrontColor = gl_Color; +} diff --git a/examples/shader/resources/text-background.png b/examples/shader/resources/text-background.png new file mode 100644 index 00000000..c86e9b6c Binary files /dev/null and b/examples/shader/resources/text-background.png differ diff --git a/examples/shader/resources/wave.jpg b/examples/shader/resources/wave.jpg deleted file mode 100644 index cd125b8c..00000000 Binary files a/examples/shader/resources/wave.jpg and /dev/null differ diff --git a/examples/shader/resources/wave.sfx b/examples/shader/resources/wave.sfx deleted file mode 100644 index ec5aaf75..00000000 --- a/examples/shader/resources/wave.sfx +++ /dev/null @@ -1,12 +0,0 @@ -uniform sampler2D texture; -uniform sampler2D wave; -uniform vec2 offset; - -void main() -{ - vec2 texoffset = vec2(texture2D(wave, (gl_TexCoord[0].xy * offset).xy)); - texoffset -= vec2(0.5, 0.5); - texoffset *= 0.05; - - gl_FragColor = texture2D(texture, gl_TexCoord[0].xy + texoffset) * gl_Color; -} diff --git a/examples/shader/resources/wave.vert b/examples/shader/resources/wave.vert new file mode 100644 index 00000000..5089cfbb --- /dev/null +++ b/examples/shader/resources/wave.vert @@ -0,0 +1,15 @@ +uniform float wave_phase; +uniform vec2 wave_amplitude; + +void main() +{ + vec4 vertex = gl_Vertex; + vertex.x += cos(gl_Vertex.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x + + sin(gl_Vertex.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3; + vertex.y += sin(gl_Vertex.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y + + cos(gl_Vertex.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3; + + gl_Position = gl_ModelViewProjectionMatrix * vertex; + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; + gl_FrontColor = gl_Color; +} diff --git a/examples/sound/Sound.cpp b/examples/sound/Sound.cpp index 8215d48b..fd31ce7a 100644 --- a/examples/sound/Sound.cpp +++ b/examples/sound/Sound.cpp @@ -35,7 +35,8 @@ void PlaySound() sf::Sleep(100); // Display the playing position - std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << sound.GetPlayingOffset() << " sec "; + std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << sound.GetPlayingOffset() / 1000.f << " sec "; + std::cout << std::flush; } std::cout << std::endl << std::endl; } @@ -68,7 +69,8 @@ void PlayMusic() sf::Sleep(100); // Display the playing position - std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << music.GetPlayingOffset() << " sec "; + std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << music.GetPlayingOffset() / 1000.f << " sec "; + std::cout << std::flush; } std::cout << std::endl; } diff --git a/examples/sound_capture/SoundCapture.cpp b/examples/sound_capture/SoundCapture.cpp index 83e85009..41b7da76 100644 --- a/examples/sound_capture/SoundCapture.cpp +++ b/examples/sound_capture/SoundCapture.cpp @@ -76,7 +76,8 @@ int main() while (sound.GetStatus() == sf::Sound::Playing) { // Display the playing position - std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << sound.GetPlayingOffset() << " sec"; + std::cout << "\rPlaying... " << std::fixed << std::setprecision(2) << sound.GetPlayingOffset() / 1000.f << " sec"; + std::cout << std::flush; // Leave some CPU time for other threads sf::Sleep(100); diff --git a/examples/win32/Win32.cpp b/examples/win32/Win32.cpp index 97c94e42..34db7907 100644 --- a/examples/win32/Win32.cpp +++ b/examples/win32/Win32.cpp @@ -81,8 +81,8 @@ INT WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, INT) return EXIT_FAILURE; sf::Sprite sprite1(texture1); sf::Sprite sprite2(texture2); - sprite1.SetOrigin(sprite1.GetSize() / 2.f); - sprite1.SetPosition(sprite1.GetSize() / 2.f); + sprite1.SetOrigin(texture1.GetWidth() / 2.f, texture1.GetHeight() / 2.f); + sprite1.SetPosition(sprite1.GetOrigin()); // Create a clock for measuring elapsed time sf::Clock clock; @@ -100,16 +100,18 @@ INT WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, INT) } else { + sf::Uint32 time = clock.GetElapsedTime(); + // Clear views SFMLView1.Clear(); SFMLView2.Clear(); // Draw sprite 1 on view 1 - sprite1.SetRotation(clock.GetElapsedTime() * 0.1f); + sprite1.SetRotation(time * 0.1f); SFMLView1.Draw(sprite1); // Draw sprite 2 on view 2 - sprite2.SetX(cos(clock.GetElapsedTime() * 0.001f) * 100.f); + sprite2.SetPosition(std::cos(time * 0.001f) * 100.f, 0.f); SFMLView2.Draw(sprite2); // Display each view on screen diff --git a/include/SFML/Graphics.hpp b/include/SFML/Graphics.hpp index ba994331..31e18c92 100644 --- a/include/SFML/Graphics.hpp +++ b/include/SFML/Graphics.hpp @@ -30,18 +30,25 @@ //////////////////////////////////////////////////////////// #include +#include #include #include #include #include -#include +#include #include #include #include #include +#include +#include +#include #include #include #include +#include +#include +#include #include diff --git a/include/SFML/Graphics/BlendMode.hpp b/include/SFML/Graphics/BlendMode.hpp new file mode 100644 index 00000000..448903bd --- /dev/null +++ b/include/SFML/Graphics/BlendMode.hpp @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_BLENDMODE_HPP +#define SFML_BLENDMODE_HPP + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \ingroup graphics +/// \brief Available blending modes for drawing +/// +//////////////////////////////////////////////////////////// +enum BlendMode +{ + BlendAlpha, ///< Pixel = Source * Source.a + Dest * (1 - Source.a) + BlendAdd, ///< Pixel = Source + Dest + BlendMultiply, ///< Pixel = Source * Dest + BlendNone ///< Pixel = Source +}; + +} // namespace sf + + +#endif // SFML_BLENDMODE_HPP diff --git a/include/SFML/Graphics/CircleShape.hpp b/include/SFML/Graphics/CircleShape.hpp new file mode 100644 index 00000000..446dcc36 --- /dev/null +++ b/include/SFML/Graphics/CircleShape.hpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CIRCLESHAPE_HPP +#define SFML_CIRCLESHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a circle +/// +//////////////////////////////////////////////////////////// +class SFML_API CircleShape : public Shape +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param radius Radius of the circle + /// \param pointsCount Number of points composing the circle + /// + //////////////////////////////////////////////////////////// + explicit CircleShape(float radius = 0, unsigned int pointsCount = 30); + + //////////////////////////////////////////////////////////// + /// \brief Set the radius of the circle + /// + /// \param radius New radius of the circle + /// + /// \see GetRadius + /// + //////////////////////////////////////////////////////////// + void SetRadius(float radius); + + //////////////////////////////////////////////////////////// + /// \brief Get the radius of the circle + /// + /// \return Radius of the circle + /// + /// \see SetRadius + /// + //////////////////////////////////////////////////////////// + float GetRadius() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the circle + /// + /// \param count New number of points of the circle + /// + /// \see GetPointsCount + /// + //////////////////////////////////////////////////////////// + void SetPointsCount(unsigned int count); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points of the shape + /// + /// \return Number of points of the shape + /// + /// \see SetPointsCount + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetPointsCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a point of the shape + /// + /// \param index Index of the point to get + /// + /// \return Index-th point of the shape + /// + //////////////////////////////////////////////////////////// + virtual Vector2f GetPoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float myRadius; ///< Radius of the circle + unsigned int myPointsCount; ///< Number of points composing the circle +}; + +} // namespace sf + + +#endif // SFML_CIRCLESHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::CircleShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// Usage example: +/// \code +/// sf::CircleShape circle; +/// circle.SetRadius(150); +/// circle.SetOutlineColor(sf::Color::Red); +/// circle.SetOutlineThickness(5); +/// circle.SetPosition(10, 20); +/// ... +/// window.Draw(circle); +/// \endcode +/// +/// Since the graphics card can't draw perfect circles, we have to +/// fake them with multiple triangles connected to each other. The +/// "points count" property of sf::CircleShape defines how many of these +/// triangles to use, and therefore defines the quality of the circle. +/// +/// The number of points can also be used for another purpose; with +/// small numbers you can create any regular polygon shape: +/// equilateral triangle, square, pentagon, hexagon, ... +/// +/// \see sf::Shape, sf::RectangleShape, sf::ConvexShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Color.hpp b/include/SFML/Graphics/Color.hpp index 8307ad72..4838239d 100644 --- a/include/SFML/Graphics/Color.hpp +++ b/include/SFML/Graphics/Color.hpp @@ -64,14 +64,15 @@ public : //////////////////////////////////////////////////////////// // Static member data //////////////////////////////////////////////////////////// - static const Color Black; ///< Black predefined color - static const Color White; ///< White predefined color - static const Color Red; ///< Red predefined color - static const Color Green; ///< Green predefined color - static const Color Blue; ///< Blue predefined color - static const Color Yellow; ///< Yellow predefined color - static const Color Magenta; ///< Magenta predefined color - static const Color Cyan; ///< Cyan predefined color + static const Color Black; ///< Black predefined color + static const Color White; ///< White predefined color + static const Color Red; ///< Red predefined color + static const Color Green; ///< Green predefined color + static const Color Blue; ///< Blue predefined color + static const Color Yellow; ///< Yellow predefined color + static const Color Magenta; ///< Magenta predefined color + static const Color Cyan; ///< Cyan predefined color + static const Color Transparent; ///< Transparent (black) predefined color //////////////////////////////////////////////////////////// // Member data @@ -197,27 +198,28 @@ SFML_API Color& operator *=(Color& left, const Color& right); /// manipulated very easily: /// /// \code -/// sf::Color c1(255, 0, 0); // red -/// c1.red = 0; // make it black -/// c1.blue = 128; // make it dark blue +/// sf::Color color(255, 0, 0); // red +/// color.red = 0; // make it black +/// color.blue = 128; // make it dark blue /// \endcode /// /// The fourth component of colors, named "alpha", represents /// the opacity of the color. A color with an alpha value of /// 255 will be fully opaque, while an alpha value of 0 will /// make a color fully transparent, whatever the value of the -/// other components. +/// other components is. /// /// The most common colors are already defined as static variables: /// \code -/// sf::Color black = sf::Color::Black; -/// sf::Color white = sf::Color::White; -/// sf::Color red = sf::Color::Red; -/// sf::Color green = sf::Color::Green; -/// sf::Color blue = sf::Color::Blue; -/// sf::Color yellow = sf::Color::Yellow; -/// sf::Color magenta = sf::Color::Magenta; -/// sf::Color cyan = sf::Color::Cyan; +/// sf::Color black = sf::Color::Black; +/// sf::Color white = sf::Color::White; +/// sf::Color red = sf::Color::Red; +/// sf::Color green = sf::Color::Green; +/// sf::Color blue = sf::Color::Blue; +/// sf::Color yellow = sf::Color::Yellow; +/// sf::Color magenta = sf::Color::Magenta; +/// sf::Color cyan = sf::Color::Cyan; +/// sf::Color transparent = sf::Color::Transparent; /// \endcode /// /// Colors can also be added and modulated (multiplied) using the diff --git a/include/SFML/Graphics/ConvexShape.hpp b/include/SFML/Graphics/ConvexShape.hpp new file mode 100644 index 00000000..771f1521 --- /dev/null +++ b/include/SFML/Graphics/ConvexShape.hpp @@ -0,0 +1,142 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_CONVEXSHAPE_HPP +#define SFML_CONVEXSHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a convex polygon +/// +//////////////////////////////////////////////////////////// +class SFML_API ConvexShape : public Shape +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param pointsCount Number of points of the polygon + /// + //////////////////////////////////////////////////////////// + explicit ConvexShape(unsigned int pointsCount = 0); + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the polygon + /// + /// \param count New number of points of the polygon + /// + /// \see GetPointsCount + /// + //////////////////////////////////////////////////////////// + void SetPointsCount(unsigned int count); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points of the polygon + /// + /// \return Number of points of the polygon + /// + /// \see SetPointsCount + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetPointsCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the position of a point + /// + /// Don't forget that the polygon must remain convex, and + /// the points need to stay ordered! + /// + /// \param index Index of the point to change + /// \param point New position of the point + /// + /// \see GetPoint + /// + //////////////////////////////////////////////////////////// + void SetPoint(unsigned int index, const Vector2f& point); + + //////////////////////////////////////////////////////////// + /// \brief Get the position of a point + /// + /// \param index Index of the point to get + /// + /// \return Position of the index-th point of the polygon + /// + /// \see SetPoint + /// + //////////////////////////////////////////////////////////// + virtual Vector2f GetPoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector myPoints; ///< Points composing the convex polygon +}; + +} // namespace sf + + +#endif // SFML_CONVEXSHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::ConvexShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// It is important to keep in mind that a convex shape must +/// always be... convex, otherwise it may not be drawn correctly. +/// Moreover, the points must be defined in order; using a random +/// order would result in an incorrect shape. +/// +/// Usage example: +/// \code +/// sf::ConvexShape polygon; +/// polygon.SetPointsCount(3); +/// polygon.SetPoint(0, sf::Vector2f(0, 0)); +/// polygon.SetPoint(1, sf::Vector2f(0, 10)); +/// polygon.SetPoint(2, sf::Vector2f(25, 5)); +/// polygon.SetOutlineColor(sf::Color::Red); +/// polygon.SetOutlineThickness(5); +/// polygon.SetPosition(10, 20); +/// ... +/// window.Draw(polygon); +/// \endcode +/// +/// \see sf::Shape, sf::RectangleShape, sf::CircleShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Drawable.hpp b/include/SFML/Graphics/Drawable.hpp index fbee1be8..707068fd 100644 --- a/include/SFML/Graphics/Drawable.hpp +++ b/include/SFML/Graphics/Drawable.hpp @@ -28,32 +28,14 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include -#include -#include +#include +#include namespace sf { -class Renderer; class RenderTarget; -namespace Blend -{ - //////////////////////////////////////////////////////////// - /// \ingroup graphics - /// \brief Available blending modes for drawable objects - /// - //////////////////////////////////////////////////////////// - enum Mode - { - Alpha, ///< Pixel = Src * Src.a + Dest * (1 - Src.a) - Add, ///< Pixel = Src + Dest - Multiply, ///< Pixel = Src * Dest - None ///< Pixel = Src - }; -} - //////////////////////////////////////////////////////////// /// \brief Abstract base class for objects that can be drawn /// to a render target @@ -67,449 +49,24 @@ public : /// \brief Virtual destructor /// //////////////////////////////////////////////////////////// - virtual ~Drawable(); - - //////////////////////////////////////////////////////////// - /// \brief Set the position of the object - /// - /// This function completely overwrites the previous position. - /// See Move to apply an offset based on the previous position instead. - /// The default position of a drawable object is (0, 0). - /// - /// \param x X coordinate of the new position - /// \param y Y coordinate of the new position - /// - /// \see Move, SetX, SetY, GetPosition - /// - //////////////////////////////////////////////////////////// - void SetPosition(float x, float y); - - //////////////////////////////////////////////////////////// - /// \brief Set the position of the object - /// - /// This function completely overwrites the previous position. - /// See Move to apply an offset based on the previous position instead. - /// The default position of a drawable object is (0, 0). - /// - /// \param position New position - /// - /// \see Move, SetX, SetY, GetPosition - /// - //////////////////////////////////////////////////////////// - void SetPosition(const Vector2f& position); - - //////////////////////////////////////////////////////////// - /// \brief Set the X position of the object - /// - /// \param x New X coordinate - /// - /// \see SetY, SetPosition, GetPosition - /// - //////////////////////////////////////////////////////////// - void SetX(float x); - - //////////////////////////////////////////////////////////// - /// \brief Set the Y position of the object - /// - /// \param y New Y coordinate - /// - /// \see SetX, SetPosition, GetPosition - /// - //////////////////////////////////////////////////////////// - void SetY(float y); - - //////////////////////////////////////////////////////////// - /// \brief Set the scale factors of the object - /// - /// \a factorX and \a factorY must be strictly positive, - /// otherwise they are ignored. - /// This function completely overwrites the previous scale. - /// See Scale to add a factor based on the previous scale instead. - /// The default scale of a drawable object is (1, 1). - /// - /// \param factorX New horizontal scale factor - /// \param factorY New vertical scale factor - /// - /// \see Scale, SetScaleX, SetScaleY, GetScale - /// - //////////////////////////////////////////////////////////// - void SetScale(float factorX, float factorY); - - //////////////////////////////////////////////////////////// - /// \brief Set the scale factors of the object - /// - /// \a scale.x and \a scale.y must be strictly positive, - /// otherwise they are ignored. - /// This function completely overwrites the previous scale. - /// See Scale to add a factor based on the previous scale instead. - /// The default scale of a drawable object is (1, 1). - /// - /// \param factors New scale factors - /// - /// \see Scale, SetScaleX, SetScaleY, GetScale - /// - //////////////////////////////////////////////////////////// - void SetScale(const Vector2f& factors); - - //////////////////////////////////////////////////////////// - /// \brief Set the X scale factor of the object - /// - /// \a factor must be strictly positive, otherwise it is ignored. - /// - /// \param factor New horizontal scale factor - /// - /// \see SetScaleY, SetScale, GetScale - /// - //////////////////////////////////////////////////////////// - void SetScaleX(float factor); - - //////////////////////////////////////////////////////////// - /// \brief Set the Y scale factor of the object - /// - /// \a factor must be strictly positive, otherwise it is ignored. - /// - /// \param factor New vertical scale factor - /// - /// \see SetScaleX, SetScale, GetScale - /// - //////////////////////////////////////////////////////////// - void SetScaleY(float factor); - - //////////////////////////////////////////////////////////// - /// \brief Set the local origin of the object - /// - /// The origin of an object defines the center point for - /// all transformations (position, scale, rotation). - /// The coordinates of this point must be relative to the - /// top-left corner of the object, and ignore all - /// transformations (position, scale, rotation). - /// The default origin of a drawable object is (0, 0). - /// - /// \param x X coordinate of the new origin - /// \param y Y coordinate of the new origin - /// - /// \see GetOrigin - /// - //////////////////////////////////////////////////////////// - void SetOrigin(float x, float y); - - //////////////////////////////////////////////////////////// - /// \brief Set the local origin of the object - /// - /// The origin of an object defines the center point for - /// all transformations (position, scale, rotation). - /// The coordinates of this point must be relative to the - /// top-left corner of the object, and ignore all - /// transformations (position, scale, rotation). - /// The default origin of a drawable object is (0, 0). - /// - /// \param origin New origin - /// - /// \see GetOrigin - /// - //////////////////////////////////////////////////////////// - void SetOrigin(const Vector2f& origin); - - //////////////////////////////////////////////////////////// - /// \brief Set the orientation of the object - /// - /// This function completely overwrites the previous rotation. - /// See Rotate to add an angle based on the previous rotation instead. - /// The default rotation of a drawable object is 0. - /// - /// \param angle New rotation, in degrees - /// - /// \see Rotate, GetRotation - /// - //////////////////////////////////////////////////////////// - void SetRotation(float angle); - - //////////////////////////////////////////////////////////// - /// \brief Set the global color of the object - /// - /// This global color affects the entire object, and modulates - /// (multiplies) its original pixels. - /// The default color is white. - /// - /// \param color New color - /// - /// \see GetColor - /// - //////////////////////////////////////////////////////////// - void SetColor(const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Set the blending mode of the object - /// - /// This property defines how the pixels of an object are - /// blended with the pixels of the render target to which - /// it is drawn. To know more about the blending modes - /// available, see the sf::Blend::Mode enum. - /// The default blend mode is Blend::Alpha. - /// - /// \param mode New blending mode - /// - /// \see GetBlendMode - /// - //////////////////////////////////////////////////////////// - void SetBlendMode(Blend::Mode mode); - - //////////////////////////////////////////////////////////// - /// \brief Get the position of the object - /// - /// \return Current position - /// - /// \see SetPosition - /// - //////////////////////////////////////////////////////////// - const Vector2f& GetPosition() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the current scale of the object - /// - /// \return Current scale factors - /// - /// \see SetScale - /// - //////////////////////////////////////////////////////////// - const Vector2f& GetScale() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the local origin of the object - /// - /// \return Current origin - /// - /// \see SetOrigin - /// - //////////////////////////////////////////////////////////// - const Vector2f& GetOrigin() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the orientation of the object - /// - /// The rotation is always in the range [0, 360]. - /// - /// \return Current rotation, in degrees - /// - /// \see SetRotation - /// - //////////////////////////////////////////////////////////// - float GetRotation() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the color of the object - /// - /// \return Current color - /// - /// \see SetColor - /// - //////////////////////////////////////////////////////////// - const Color& GetColor() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the blend mode of the object - /// - /// \return Current blend mode - /// - /// \see SetBlendMode - /// - //////////////////////////////////////////////////////////// - Blend::Mode GetBlendMode() const; - - //////////////////////////////////////////////////////////// - /// \brief Move the object by a given offset - /// - /// This function adds to the current position of the object, - /// unlike SetPosition which overwrites it. - /// Thus, it is equivalent to the following code: - /// \code - /// sf::Vector2f pos = object.GetPosition(); - /// object.SetPosition(pos.x + offsetX, pos.y + offsetY); - /// \endcode - /// - /// \param offsetX X offset - /// \param offsetY Y offset - /// - /// \see SetPosition - /// - //////////////////////////////////////////////////////////// - void Move(float offsetX, float offsetY); - - //////////////////////////////////////////////////////////// - /// \brief Move the object by a given offset - /// - /// This function adds to the current position of the object, - /// unlike SetPosition which overwrites it. - /// Thus, it is equivalent to the following code: - /// \code - /// object.SetPosition(object.GetPosition() + offset); - /// \endcode - /// - /// \param offset Offset - /// - /// \see SetPosition - /// - //////////////////////////////////////////////////////////// - void Move(const Vector2f& offset); - - //////////////////////////////////////////////////////////// - /// \brief Scale the object - /// - /// This function multiplies the current scale of the object, - /// unlike SetScale which overwrites it. - /// Thus, it is equivalent to the following code: - /// \code - /// sf::Vector2f scale = object.GetScale(); - /// object.SetScale(scale.x * factorX, scale.y * factorY); - /// \endcode - /// - /// \param factorX Horizontal scale factor - /// \param factorY Vertical scale factor - /// - /// \see SetScale - /// - //////////////////////////////////////////////////////////// - void Scale(float factorX, float factorY); - - //////////////////////////////////////////////////////////// - /// \brief Scale the object - /// - /// This function multiplies the current scale of the object, - /// unlike SetScale which overwrites it. - /// Thus, it is equivalent to the following code: - /// \code - /// sf::Vector2f scale = object.GetScale(); - /// object.SetScale(scale.x * factor.x, scale.y * factor.y); - /// \endcode - /// - /// \param factor Scale factors - /// - /// \see SetScale - /// - //////////////////////////////////////////////////////////// - void Scale(const Vector2f& factor); - - //////////////////////////////////////////////////////////// - /// \brief Rotate the object - /// - /// This function ads to the current rotation of the object, - /// unlike SetRotation which overwrites it. - /// Thus, it is equivalent to the following code: - /// \code - /// object.SetRotation(object.GetRotation() + angle); - /// \endcode - /// - /// \param angle Angle of rotation, in degrees - /// - //////////////////////////////////////////////////////////// - void Rotate(float angle); - - //////////////////////////////////////////////////////////// - /// \brief Transform a point in object local coordinates - /// - /// This function takes a point in global coordinates, and - /// transforms it in coordinates local to the object. - /// In other words, it applies the inverse of all the - /// transformations applied to the object (origin, - /// translation, rotation and scale). - /// - /// \param point Point to transform - /// - /// \return The transformed point - /// - /// \see TransformToGlobal - /// - //////////////////////////////////////////////////////////// - Vector2f TransformToLocal(const Vector2f& point) const; - - //////////////////////////////////////////////////////////// - /// \brief Transform a local point in global coordinates - /// - /// This function takes a point in local coordinates, and - /// transforms it in global coordinates. In other words, - /// it applies the same transformations that are applied - /// to the object (origin, translation, rotation and scale). - /// - /// \param point Point to transform - /// - /// \return The transformed point - /// - /// \see TransformToLocal - /// - //////////////////////////////////////////////////////////// - Vector2f TransformToGlobal(const Vector2f& point) const; - -protected : - - //////////////////////////////////////////////////////////// - /// \brief Default constructor - /// - //////////////////////////////////////////////////////////// - Drawable(); - - //////////////////////////////////////////////////////////// - /// \brief Get the transform matrix of the object - /// - /// \return Transform matrix - /// - /// \see GetInverseMatrix - /// - //////////////////////////////////////////////////////////// - const Matrix3& GetMatrix() const; - - //////////////////////////////////////////////////////////// - /// \brief Get the inverse transform matrix of the object - /// - /// \return Inverse transform matrix - /// - /// \see GetMatrix - /// - //////////////////////////////////////////////////////////// - const Matrix3& GetInverseMatrix() const; + virtual ~Drawable() {} private : friend class RenderTarget; - //////////////////////////////////////////////////////////// - /// \brief Draw the object to a render target - /// - /// This function applies the common states of the object, - /// then calls the virtual Render functions to let the derived - /// class draw the geometry of the object. - /// - /// \param target Render target - /// \param renderer Renderer providing low-level rendering commands - /// - //////////////////////////////////////////////////////////// - void Draw(RenderTarget& target, Renderer& renderer) const; - //////////////////////////////////////////////////////////// /// \brief Draw the object to a render target /// /// This is a pure virtual function that has to be implemented /// by the derived class to define how the drawable should be - /// rendered. + /// drawn. /// - /// \param target Render target - /// \param renderer Renderer providing low-level rendering commands + /// \param target Render target to draw to + /// \param states Current render states /// //////////////////////////////////////////////////////////// - virtual void Render(RenderTarget& target, Renderer& renderer) const = 0; - - //////////////////////////////////////////////////////////// - // Member data - //////////////////////////////////////////////////////////// - Vector2f myPosition; ///< Position of the object on screen - Vector2f myScale; ///< Scale of the object - Vector2f myOrigin; ///< Origin of translation / rotation / scaling of the object - float myRotation; ///< Orientation of the object, in degrees - Color myColor; ///< Overlay color of the object - Blend::Mode myBlendMode; ///< Blending mode - mutable Matrix3 myMatrix; ///< Precomputed transform matrix gathering the translation / rotation / scale / center - mutable Matrix3 myInvMatrix; ///< Precomputed inverse transform matrix gathering the translation / rotation / scale / center - mutable bool myMatrixUpdated; ///< Do we need to recompute the transform matrix ? - mutable bool myInvMatrixUpdated; ///< Do we need to recompute the inverse transform matrix ? + virtual void Draw(RenderTarget& target, RenderStates states) const = 0; }; } // namespace sf @@ -522,44 +79,16 @@ private : /// \class sf::Drawable /// \ingroup graphics /// -/// sf::Drawable defines the attributes and operations that -/// are common to all the drawable classes: -/// \li transformations (position, rotation, scale, local origin) -/// \li global overlay color -/// \li blending mode with background pixels -/// \li the ability to be drawn on a sf::RenderTarget (either RenderWindow or RenderTexture) +/// sf::Drawable is a very simple base class that allows objects +/// of derived classes to be drawn to a sf::RenderTarget. /// -/// Please note that all these attributes are hardware accelerated, -/// therefore they are extremely cheap to use (unlike older -/// libraries that perform slow transformations on the CPU, such as -/// rotation or scale). +/// All you have to do in your derived class is to override the +/// Draw virtual function. /// -/// Usage example: -/// \code -/// // Here we'll use a sf::Sprite to demonstrate the features of sf::Drawable -/// sf::Sprite drawable = /* ...whatever... */; -/// -/// drawable.SetOrigin(10, 20); // set its origin to the local point (10, 20) -/// drawable.SetPosition(100, 100); // set its position to (100, 100) -/// drawable.SetRotation(45); // set its orientation to 45 degrees -/// drawable.SetColor(sf::Color::Red); // set its global color to red -/// drawable.SetBlendingMode(sf::Blend::Add); // set an additive blend mode -/// -/// window.Draw(drawable); // finally draw it (window is a sf::RenderWindow) -/// \endcode -/// -/// Deriving your own class from sf::Drawable is possible, however -/// you have to use the sf::Renderer class instead of direct OpenGL -/// calls, which is more limited. To create a derived drawable class, -/// all you have to do is to override the virtual Render function. -/// -/// One of the main benefits of creating your own drawable class is -/// that you can build hierarchies of drawable objects. Indeed, -/// when you draw a drawable inside the Render function of another -/// drawable, the former inherits the transformations and color of -/// the latter and combines them with its own attributes. -/// This way, you can apply global transformations/color to a set -/// of drawables as if it was a single entity. +/// Note that inheriting from sf::Drawable is not mandatory, +/// but it allows this nice syntax "window.Draw(object)" rather +/// than "object.Draw(window)", which is more consistent with other +/// SFML classes. /// /// Example: /// \code @@ -571,26 +100,27 @@ private : /// /// private : /// -/// virtual void Render(sf::RenderTarget& target, sf::Renderer& renderer) const +/// virtual void Draw(sf::RenderTarget& target, RenderStates states) const /// { -/// // Low-level geometry rendering -/// renderer.SetTexture(&myTexture); -/// renderer.Begin(sf::Renderer::QuadList); -/// renderer.AddVertex(...); -/// renderer.AddVertex(...); -/// renderer.AddVertex(...); -/// renderer.AddVertex(...); -/// renderer.End(); +/// // You can draw other high-level objects +/// target.Draw(mySprite, states); /// -/// // High-level drawable rendering -/// target.Draw(mySubSprite); +/// // ... or use the low-level API +/// states.Texture = &myTexture; +/// target.Draw(myVertices, states); +/// +/// // ... or draw with OpenGL directly +/// glBegin(GL_QUADS); +/// ... +/// glEnd(); /// } /// +/// sf::Sprite mySprite; /// sf::Texture myTexture; -/// sf::Sprite mySubSprite; +/// sf::VertexArray myVertices; /// }; /// \endcode /// -/// \see sf::Shape, sf::Sprite, sf::Text +/// \see sf::RenderTarget /// //////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Glyph.hpp b/include/SFML/Graphics/Glyph.hpp index c0a4fdaf..38ff22e7 100644 --- a/include/SFML/Graphics/Glyph.hpp +++ b/include/SFML/Graphics/Glyph.hpp @@ -51,9 +51,9 @@ public : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - int Advance; ///< Offset to move horizontically to the next character - IntRect Bounds; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline - IntRect SubRect; ///< Texture coordinates of the glyph inside the font's texture + int Advance; ///< Offset to move horizontically to the next character + IntRect Bounds; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline + IntRect TextureRect; ///< Texture coordinates of the glyph inside the font's texture }; } // namespace sf @@ -71,7 +71,7 @@ public : /// The sf::Glyph structure provides the information needed /// to handle the glyph: /// \li its coordinates in the font's texture -/// \li its bounding rect +/// \li its bounding rectangle /// \li the offset to apply to get the starting position of the next glyph /// /// \see sf::Font diff --git a/include/SFML/Graphics/Matrix3.hpp b/include/SFML/Graphics/Matrix3.hpp deleted file mode 100644 index f2bc76c0..00000000 --- a/include/SFML/Graphics/Matrix3.hpp +++ /dev/null @@ -1,176 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -#ifndef SFML_MATRIX3_HPP -#define SFML_MATRIX3_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include - - -namespace sf -{ -//////////////////////////////////////////////////////////// -/// \brief Utility class to manipulate 3x3 matrices of floats -/// -//////////////////////////////////////////////////////////// -class SFML_API Matrix3 -{ -public : - - //////////////////////////////////////////////////////////// - /// \brief Default constructor - /// - /// This constructor creates an identity matrix. - /// - //////////////////////////////////////////////////////////// - Matrix3(); - - //////////////////////////////////////////////////////////// - /// \brief Construct a matrix from its 9 elements - /// - /// \param a00 Element (0, 0) of the matrix - /// \param a01 Element (0, 1) of the matrix - /// \param a02 Element (0, 2) of the matrix - /// \param a10 Element (1, 0) of the matrix - /// \param a11 Element (1, 1) of the matrix - /// \param a12 Element (1, 2) of the matrix - /// \param a20 Element (2, 0) of the matrix - /// \param a21 Element (2, 1) of the matrix - /// \param a22 Element (2, 2) of the matrix - /// - //////////////////////////////////////////////////////////// - Matrix3(float a00, float a01, float a02, - float a10, float a11, float a12, - float a20, float a21, float a22); - - //////////////////////////////////////////////////////////// - /// \brief Transform a point by the matrix - /// - /// \param point Point to transform - /// - /// \return Transformed point - /// - //////////////////////////////////////////////////////////// - Vector2f Transform(const Vector2f& point) const; - - //////////////////////////////////////////////////////////// - /// \brief Return the inverse of the matrix - /// - /// If the inverse cannot be computed, the identity matrix - /// is returned. - /// - /// \return A new matrix which is the inverse of self - /// - //////////////////////////////////////////////////////////// - Matrix3 GetInverse() const; - - //////////////////////////////////////////////////////////// - /// \brief Return the elements of the matrix - /// - /// This function returns an array of 16 floats containing - /// the corresponding 4x4 matrix, so that it is directly - /// compatible with OpenGL functions. - /// - /// \return Pointer to the 4x4 matrix elements - /// - //////////////////////////////////////////////////////////// - const float* Get4x4Elements() const; - - //////////////////////////////////////////////////////////// - /// \brief Overload of binary operator * - /// - /// \param right Right operand of the multiplication - /// - /// \return New matrix which is the result of self * \a right - /// - //////////////////////////////////////////////////////////// - Matrix3 operator *(const Matrix3& right) const; - - //////////////////////////////////////////////////////////// - /// \brief Build a matrix from a set of transformations - /// - /// \param origin Origin for the transformations - /// \param translation Translation offset - /// \param rotation Rotation angle in degrees - /// \param scale Scaling factors - /// - /// \return New Matrix3 containing the transformations - /// - /// \see Projection - /// - //////////////////////////////////////////////////////////// - static Matrix3 Transformation(const Vector2f& origin, const Vector2f& translation, float rotation, const Vector2f& scale); - - //////////////////////////////////////////////////////////// - /// \brief Build a 2D project matrix - /// - /// \param center Center of the view - /// \param size Size of the view - /// \param rotation Angle of rotation of the view, in degrees - /// - /// \return New Matrix3 containing the projection - /// - /// \see Transformation - /// - //////////////////////////////////////////////////////////// - static Matrix3 Projection(const Vector2f& center, const Vector2f& size, float rotation); - - //////////////////////////////////////////////////////////// - // Static member data - //////////////////////////////////////////////////////////// - static const Matrix3 Identity; ///< The identity matrix - -private : - - //////////////////////////////////////////////////////////// - // Member data - //////////////////////////////////////////////////////////// - float myData[16]; /// Matrix elements (we directly store it as a 4x4 matrix for optimization purpose) -}; - -#include - -} // namespace sf - - -#endif // SFML_MATRIX3_HPP - - -//////////////////////////////////////////////////////////// -/// \class sf::Matrix3 -/// \ingroup graphics -/// -/// Matrix3 is only meant for internal use, its interface is -/// limited and its implementation is optimized for OpenGL -/// rendering. -/// -/// This type is not used at all in the public API of SFML. -/// -//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Matrix3.inl b/include/SFML/Graphics/Matrix3.inl deleted file mode 100644 index e7f7f629..00000000 --- a/include/SFML/Graphics/Matrix3.inl +++ /dev/null @@ -1,147 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////// -inline Matrix3::Matrix3() -{ - myData[0] = 1.f; myData[4] = 0.f; myData[8] = 0.f; myData[12] = 0.f; - myData[1] = 0.f; myData[5] = 1.f; myData[9] = 0.f; myData[13] = 0.f; - myData[2] = 0.f; myData[6] = 0.f; myData[10] = 1.f; myData[14] = 0.f; - myData[3] = 0.f; myData[7] = 0.f; myData[11] = 0.f; myData[15] = 1.f; -} - - -//////////////////////////////////////////////////////////// -inline Matrix3::Matrix3(float a00, float a01, float a02, - float a10, float a11, float a12, - float a20, float a21, float a22) -{ - myData[0] = a00; myData[4] = a01; myData[8] = 0.f; myData[12] = a02; - myData[1] = a10; myData[5] = a11; myData[9] = 0.f; myData[13] = a12; - myData[2] = 0.f; myData[6] = 0.f; myData[10] = 1.f; myData[14] = 0.f; - myData[3] = a20; myData[7] = a21; myData[11] = 0.f; myData[15] = a22; -} - - -//////////////////////////////////////////////////////////// -inline Vector2f Matrix3::Transform(const Vector2f& point) const -{ - return Vector2f(myData[0] * point.x + myData[4] * point.y + myData[12], - myData[1] * point.x + myData[5] * point.y + myData[13]); -} - - -//////////////////////////////////////////////////////////// -inline Matrix3 Matrix3::GetInverse() const -{ - // Compute the determinant - float det = myData[0] * (myData[15] * myData[5] - myData[7] * myData[13]) - - myData[1] * (myData[15] * myData[4] - myData[7] * myData[12]) + - myData[3] * (myData[13] * myData[4] - myData[5] * myData[12]); - - // Compute the inverse if determinant is not zero - if (det != 0.f) // don't use an epsilon because the determinant may *really* be tiny - { - return Matrix3( (myData[15] * myData[5] - myData[7] * myData[13]) / det, - -(myData[15] * myData[4] - myData[7] * myData[12]) / det, - (myData[13] * myData[4] - myData[5] * myData[12]) / det, - -(myData[15] * myData[1] - myData[3] * myData[13]) / det, - (myData[15] * myData[0] - myData[3] * myData[12]) / det, - -(myData[13] * myData[0] - myData[1] * myData[12]) / det, - (myData[7] * myData[1] - myData[3] * myData[5]) / det, - -(myData[7] * myData[0] - myData[3] * myData[4]) / det, - (myData[5] * myData[0] - myData[1] * myData[4]) / det); - } - else - { - return Identity; - } -} - - -//////////////////////////////////////////////////////////// -inline const float* Matrix3::Get4x4Elements() const -{ - return myData; -} - - -//////////////////////////////////////////////////////////// -inline Matrix3 Matrix3::operator *(const Matrix3& right) const -{ - return Matrix3(myData[0] * right.myData[0] + myData[4] * right.myData[1] + myData[12] * right.myData[3], - myData[0] * right.myData[4] + myData[4] * right.myData[5] + myData[12] * right.myData[7], - myData[0] * right.myData[12] + myData[4] * right.myData[13] + myData[12] * right.myData[15], - myData[1] * right.myData[0] + myData[5] * right.myData[1] + myData[13] * right.myData[3], - myData[1] * right.myData[4] + myData[5] * right.myData[5] + myData[13] * right.myData[7], - myData[1] * right.myData[12] + myData[5] * right.myData[13] + myData[13] * right.myData[15], - myData[3] * right.myData[0] + myData[7] * right.myData[1] + myData[15] * right.myData[3], - myData[3] * right.myData[4] + myData[7] * right.myData[5] + myData[15] * right.myData[7], - myData[3] * right.myData[12] + myData[7] * right.myData[13] + myData[15] * right.myData[15]); -} - - -//////////////////////////////////////////////////////////// -inline Matrix3 Matrix3::Transformation(const Vector2f& origin, const Vector2f& translation, float rotation, const Vector2f& scale) -{ - // Combine the transformations - float angle = -rotation * 3.141592654f / 180.f; - float cosine = static_cast(std::cos(angle)); - float sine = static_cast(std::sin(angle)); - float sxCos = scale.x * cosine; - float syCos = scale.y * cosine; - float sxSin = scale.x * sine; - float sySin = scale.y * sine; - float tx = -origin.x * sxCos - origin.y * sySin + translation.x; - float ty = origin.x * sxSin - origin.y * syCos + translation.y; - - // Construct the matrix - return Matrix3( sxCos, sySin, tx, - -sxSin, syCos, ty, - 0.f, 0.f, 1.f); -} - - -//////////////////////////////////////////////////////////// -inline Matrix3 Matrix3::Projection(const Vector2f& center, const Vector2f& size, float rotation) -{ - // Rotation components - float angle = rotation * 3.141592654f / 180.f; - float cosine = static_cast(std::cos(angle)); - float sine = static_cast(std::sin(angle)); - float tx = -center.x * cosine - center.y * sine + center.x; - float ty = center.x * sine - center.y * cosine + center.y; - - // Projection components - float a = 2.f / size.x; - float b = -2.f / size.y; - float c = -a * center.x; - float d = -b * center.y; - - // Rebuild the projection matrix - return Matrix3( a * cosine, a * sine, a * tx + c, - -b * sine, b * cosine, b * ty + d, - 0.f, 0.f, 1.f); -} diff --git a/include/SFML/Graphics/PrimitiveType.hpp b/include/SFML/Graphics/PrimitiveType.hpp new file mode 100644 index 00000000..a7458b8a --- /dev/null +++ b/include/SFML/Graphics/PrimitiveType.hpp @@ -0,0 +1,53 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_PRIMITIVETYPE_HPP +#define SFML_PRIMITIVETYPE_HPP + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \ingroup graphics +/// \brief Types of primitives that a sf::VertexArray can render +/// +/// Points and lines have no area, therefore their thickness +/// will always be 1 pixel, regarldess the current transform +/// and view. +/// +//////////////////////////////////////////////////////////// +enum PrimitiveType +{ + Points, ///< List of individual points + Lines, ///< List of individual lines + LinesStrip, ///< List of connected lines, a point uses the previous point to form a line + Triangles, ///< List of individual triangles + TrianglesStrip, ///< List of connected triangles, a point uses the two previous points to form a triangle + TrianglesFan, ///< List of connected triangles, a point uses the common center and the previous point to form a triangle + Quads ///< List of individual quads +}; + +} // namespace sf + + +#endif // SFML_PRIMITIVETYPE_HPP diff --git a/include/SFML/Graphics/Rect.hpp b/include/SFML/Graphics/Rect.hpp index 9bb3f039..0f7b1c08 100644 --- a/include/SFML/Graphics/Rect.hpp +++ b/include/SFML/Graphics/Rect.hpp @@ -154,6 +154,36 @@ public : T Height; ///< Height of the rectangle }; +//////////////////////////////////////////////////////////// +/// \relates Rect +/// \brief Overload of binary operator == +/// +/// This operator compares strict equality between two rectangles. +/// +/// \param left Left operand (a rectangle) +/// \param right Right operand (a rectangle) +/// +/// \return True if \a left is equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator ==(const Rect& left, const Rect& right); + +//////////////////////////////////////////////////////////// +/// \relates Rect +/// \brief Overload of binary operator != +/// +/// This operator compares strict difference between two rectangles. +/// +/// \param left Left operand (a rectangle) +/// \param right Right operand (a rectangle) +/// +/// \return True if \a left is not equal to \a right +/// +//////////////////////////////////////////////////////////// +template +bool operator !=(const Rect& left, const Rect& right); + #include // Create typedefs for the most common types diff --git a/include/SFML/Graphics/Rect.inl b/include/SFML/Graphics/Rect.inl index 98688511..e978758f 100644 --- a/include/SFML/Graphics/Rect.inl +++ b/include/SFML/Graphics/Rect.inl @@ -118,3 +118,21 @@ bool Rect::Intersects(const Rect& rectangle, Rect& intersection) const return false; } } + + +//////////////////////////////////////////////////////////// +template +inline bool operator ==(const Rect& left, const Rect& right) +{ + return (left.Left == right.Left) && (left.Width == right.Width) && + (left.Top == right.Top) && (left.Height == right.Height); +} + + +//////////////////////////////////////////////////////////// +template +inline bool operator !=(const Rect& left, const Rect& right) +{ + return (left.Left != right.Left) || (left.Width != right.Width) || + (left.Top != right.Top) || (left.Height != right.Height); +} diff --git a/include/SFML/Graphics/RectangleShape.hpp b/include/SFML/Graphics/RectangleShape.hpp new file mode 100644 index 00000000..6d3b4c04 --- /dev/null +++ b/include/SFML/Graphics/RectangleShape.hpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RECTANGLESHAPE_HPP +#define SFML_RECTANGLESHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a rectangle +/// +//////////////////////////////////////////////////////////// +class SFML_API RectangleShape : public Shape +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// \param size Size of the rectangle + /// + //////////////////////////////////////////////////////////// + explicit RectangleShape(const Vector2f& size = Vector2f(0, 0)); + + //////////////////////////////////////////////////////////// + /// \brief Set the size of the rectangle + /// + /// \param size New size of the rectangle + /// + /// \see GetSize + /// + //////////////////////////////////////////////////////////// + void SetSize(const Vector2f& size); + + //////////////////////////////////////////////////////////// + /// \brief Get the size of the rectangle + /// + /// \return Size of the rectangle + /// + /// \see SetSize + /// + //////////////////////////////////////////////////////////// + const Vector2f& GetSize() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetPointsCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a point of the shape + /// + /// \param index Index of the point to get + /// + /// \return Index-th point of the shape + /// + //////////////////////////////////////////////////////////// + virtual Vector2f GetPoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f mySize; ///< Size of the rectangle +}; + +} // namespace sf + + +#endif // SFML_RECTANGLESHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RectangleShape +/// \ingroup graphics +/// +/// This class inherits all the functions of sf::Transformable +/// (position, rotation, scale, bounds, ...) as well as the +/// functions of sf::Shape (outline, color, texture, ...). +/// +/// Usage example: +/// \code +/// sf::RectangleShape rectangle; +/// rectangle.SetSize(sf::Vector2f(100, 50)); +/// rectangle.SetOutlineColor(sf::Color::Red); +/// rectangle.SetOutlineThickness(5); +/// rectangle.SetPosition(10, 20); +/// ... +/// window.Draw(rectangle); +/// \endcode +/// +/// \see sf::Shape, sf::CircleShape, sf::ConvexShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderStates.hpp b/include/SFML/Graphics/RenderStates.hpp new file mode 100644 index 00000000..13d09d99 --- /dev/null +++ b/include/SFML/Graphics/RenderStates.hpp @@ -0,0 +1,173 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_RENDERSTATES_HPP +#define SFML_RENDERSTATES_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +class Shader; +class Texture; + +//////////////////////////////////////////////////////////// +/// \brief Define the states used for drawing to a RenderTarget +/// +//////////////////////////////////////////////////////////// +class SFML_API RenderStates +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Constructing a default set of render states is equivalent + /// to using sf::RenderStates::Default. + /// The default set defines: + /// \li the BlendAlpha blend mode + /// \li the identity transform + /// \li a null texture + /// \li a null shader + /// + //////////////////////////////////////////////////////////// + RenderStates(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom blend mode + /// + /// \param blendMode Blend mode to use + /// + //////////////////////////////////////////////////////////// + RenderStates(sf::BlendMode blendMode); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom transform + /// + /// \param transform Transform to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const sf::Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom texture + /// + /// \param texture Texture to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const sf::Texture* texture); + + //////////////////////////////////////////////////////////// + /// \brief Construct a default set of render states with a custom shader + /// + /// \param shader Shader to use + /// + //////////////////////////////////////////////////////////// + RenderStates(const sf::Shader* shader); + + //////////////////////////////////////////////////////////// + /// \brief Construct a set of render states with all its attributes + /// + /// \param blendMode Blend mode to use + /// \param transform Transform to use + /// \param texture Texture to use + /// \param shader Shader to use + /// + //////////////////////////////////////////////////////////// + RenderStates(sf::BlendMode blendMode, const sf::Transform& transform, + const sf::Texture* texture, const sf::Shader* shader); + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const RenderStates Default; ///< Special instance holding the default render states + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + sf::BlendMode BlendMode; ///< Blending mode + sf::Transform Transform; ///< Transform + const sf::Texture* Texture; ///< Texture + const sf::Shader* Shader; ///< Shader +}; + +} // namespace sf + + +#endif // SFML_RENDERSTATES_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::RenderStates +/// \ingroup graphics +/// +/// There are four global states that can be applied to +/// the drawn objects: +/// \li the blend mode: how pixels of the object are blended with the background +/// \li the transform: how the object is positioned/rotated/scaled +/// \li the texture: what image is mapped to the object +/// \li the shader: what custom effect is applied to the object +/// +/// High-level objects such as sprites or text force some of +/// these states when they are drawn. For example, a sprite +/// will set its own texture, so that you don't have to care +/// about it when drawing the sprite. +/// +/// The transform is a special case: sprites, texts and shapes +/// (and it's a good idea to do it with your own drawable classes +/// too) combine their transform with the one that is passed in the +/// RenderStates structure. So that you can use a "global" transform +/// on top of each object's transform. +/// +/// Most objects, especially high-level drawables, can be drawn +/// directly without defining render states explicitely -- the +/// default set of states is ok in most cases. +/// \code +/// window.Draw(sprite); +/// \endcode +/// +/// If you want to use a single specific render state, +/// for example a shader, you can pass it directly to the Draw +/// function: sf::RenderStates has an implicit one-argument +/// constructor for each state. +/// \code +/// window.Draw(sprite, shader); +/// \endcode +/// +/// When you're inside the Draw function of a drawable +/// object (inherited from sf::Drawable), you can +/// either pass the render states unmodified, or change +/// some of them. +/// For example, a transformable object will combine the +/// current transform with its own transform. A sprite will +/// set its texture. Etc. +/// +/// \see sf::RenderTarget, sf::Drawable +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/RenderTarget.hpp b/include/SFML/Graphics/RenderTarget.hpp index 961a26a2..e87ffc3b 100644 --- a/include/SFML/Graphics/RenderTarget.hpp +++ b/include/SFML/Graphics/RenderTarget.hpp @@ -31,14 +31,17 @@ #include #include #include -#include #include +#include +#include +#include +#include +#include namespace sf { class Drawable; -class Shader; //////////////////////////////////////////////////////////// /// \brief Base class for all render targets (window, texture, ...) @@ -65,61 +68,17 @@ public : //////////////////////////////////////////////////////////// void Clear(const Color& color = Color(0, 0, 0, 255)); - //////////////////////////////////////////////////////////// - /// \brief Draw an object into the target - /// - /// This function draws anything that inherits from the - /// sf::Drawable base class (sf::Sprite, sf::Shape, sf::Text, - /// or even your own derived classes). - /// - /// \param object Object to draw - /// - //////////////////////////////////////////////////////////// - void Draw(const Drawable& object); - - //////////////////////////////////////////////////////////// - /// \brief Draw an object into the target with a shader - /// - /// This function draws anything that inherits from the - /// sf::Drawable base class (sf::Sprite, sf::Shape, sf::Text, - /// or even your own derived classes). - /// The shader alters the way that the pixels are processed - /// right before being written to the render target. - /// - /// \param object Object to draw - /// \param shader Shader to use for drawing the object - /// - //////////////////////////////////////////////////////////// - void Draw(const Drawable& object, const Shader& shader); - - //////////////////////////////////////////////////////////// - /// \brief Return the width of the rendering region of the target - /// - /// \return Width in pixels - /// - /// \see GetHeight - /// - //////////////////////////////////////////////////////////// - virtual unsigned int GetWidth() const = 0; - - //////////////////////////////////////////////////////////// - /// \brief Return the height of the rendering region of the target - /// - /// \return Height in pixels - /// - /// \see GetWidth - /// - //////////////////////////////////////////////////////////// - virtual unsigned int GetHeight() const = 0; - //////////////////////////////////////////////////////////// /// \brief Change the current active view /// + /// The view is like a 2D camera, it controls which part of + /// the 2D scene is visible, and how it is viewed in the + /// render-target. /// The new view will affect everything that is drawn, until - /// another view is activated. + /// another view is set. /// The render target keeps its own copy of the view object, /// so it is not necessary to keep the original one alive - /// as long as it is in use. + /// after calling this function. /// To restore the original view of the target, you can pass /// the result of GetDefaultView() to this function. /// @@ -131,7 +90,7 @@ public : void SetView(const View& view); //////////////////////////////////////////////////////////// - /// \brief Retrieve the view currently in use in the render target + /// \brief Get the view currently in use in the render target /// /// \return The view object that is currently used /// @@ -218,11 +177,52 @@ public : //////////////////////////////////////////////////////////// Vector2f ConvertCoords(unsigned int x, unsigned int y, const View& view) const; + //////////////////////////////////////////////////////////// + /// \brief Draw a drawable object to the render-target + /// + /// \param drawable Object to draw + /// \param states Render states to use for drawing + /// + //////////////////////////////////////////////////////////// + void Draw(const Drawable& drawable, const RenderStates& states = RenderStates::Default); + + //////////////////////////////////////////////////////////// + /// \brief Draw primitives defined by an array of vertices + /// + /// \param vertices Pointer to the vertices + /// \param verticesCount Number of vertices in the array + /// \param type Type of primitives to draw + /// \param states Render states to use for drawing + /// + //////////////////////////////////////////////////////////// + void Draw(const Vertex* vertices, unsigned int verticesCount, + PrimitiveType type, const RenderStates& states = RenderStates::Default); + + //////////////////////////////////////////////////////////// + /// \brief Return the width of the rendering region of the target + /// + /// \return Width in pixels + /// + /// \see GetHeight + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetWidth() const = 0; + + //////////////////////////////////////////////////////////// + /// \brief Return the height of the rendering region of the target + /// + /// \return Height in pixels + /// + /// \see GetWidth + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetHeight() const = 0; + //////////////////////////////////////////////////////////// /// \brief Save the current OpenGL render states and matrices /// /// This function can be used when you mix SFML drawing - /// and direct OpenGL rendering. Combined with RestoreGLStates, + /// and direct OpenGL rendering. Combined with PopGLStates, /// it ensures that: /// \li SFML's internal states are not messed up by your OpenGL code /// \li your OpenGL states are not modified by a call to a SFML function @@ -231,34 +231,60 @@ public : /// calls Draw functions. Example: /// \code /// // OpenGL code here... - /// window.SaveGLStates(); + /// window.PushGLStates(); /// window.Draw(...); /// window.Draw(...); - /// window.RestoreGLStates(); + /// window.PopGLStates(); /// // OpenGL code here... /// \endcode /// - /// Note that this function is quite expensive and should be - /// used wisely. It is provided for convenience, and the best - /// results will be achieved if you handle OpenGL states - /// yourself (because you really know which states have really - /// changed, and need to be saved / restored). + /// Note that this function is quite expensive: it saves all the + /// possible OpenGL states and matrices, even the ones you + /// don't care about. Therefore it should be used wisely. + /// It is provided for convenience, but the best results will + /// be achieved if you handle OpenGL states yourself (because + /// you know which states have really changed, and need to be + /// saved and restored). Take a look at the ResetGLStates + /// function if you do so. /// - /// \see RestoreGLStates + /// \see PopGLStates /// //////////////////////////////////////////////////////////// - void SaveGLStates(); + void PushGLStates(); //////////////////////////////////////////////////////////// /// \brief Restore the previously saved OpenGL render states and matrices /// - /// See the description of SaveGLStates to get a detailed + /// See the description of PushGLStates to get a detailed /// description of these functions. /// - /// \see SaveGLStates + /// \see PushGLStates /// //////////////////////////////////////////////////////////// - void RestoreGLStates(); + void PopGLStates(); + + //////////////////////////////////////////////////////////// + /// \brief Reset the internal OpenGL states so that the target is ready for drawing + /// + /// This function can be used when you mix SFML drawing + /// and direct OpenGL rendering, if you choose not to use + /// PushGLStates/PopGLStates. It makes sure that all OpenGL + /// states needed by SFML are set, so that subsequent Draw() + /// calls will work as expected. + /// + /// Example: + /// \code + /// // OpenGL code here... + /// glPushAttrib(...); + /// window.ResetGLStates(); + /// window.Draw(...); + /// window.Draw(...); + /// glPopAttrib(...); + /// // OpenGL code here... + /// \endcode + /// + //////////////////////////////////////////////////////////// + void ResetGLStates(); protected : @@ -277,6 +303,44 @@ protected : //////////////////////////////////////////////////////////// void Initialize(); + //////////////////////////////////////////////////////////// + /// \brief Apply the current view + /// + //////////////////////////////////////////////////////////// + void ApplyCurrentView(); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new blending mode + /// + /// \param mode Blending mode to apply + /// + //////////////////////////////////////////////////////////// + void ApplyBlendMode(BlendMode mode); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new transform + /// + /// \param transform Transform to apply + /// + //////////////////////////////////////////////////////////// + void ApplyTransform(const Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new texture + /// + /// \param texture Texture to apply + /// + //////////////////////////////////////////////////////////// + void ApplyTexture(const Texture* texture); + + //////////////////////////////////////////////////////////// + /// \brief Apply a new shader + /// + /// \param shader Shader to apply + /// + //////////////////////////////////////////////////////////// + void ApplyShader(const Shader* shader); + private : //////////////////////////////////////////////////////////// @@ -293,14 +357,27 @@ private : //////////////////////////////////////////////////////////// virtual bool Activate(bool active) = 0; + //////////////////////////////////////////////////////////// + /// \brief Render states cache + /// + //////////////////////////////////////////////////////////// + struct StatesCache + { + enum {VertexCacheSize = 4}; + + bool ViewChanged; ///< Has the current view changed since last draw? + BlendMode LastBlendMode; ///< Cached blending mode + Uint64 LastTextureId; ///< Cached texture + bool UseVertexCache; ///< Did we previously use the vertex cache? + Vertex VertexCache[VertexCacheSize]; ///< Pre-transformed vertices cache + }; + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - Renderer myRenderer; ///< Renderer that will process the rendering commands of the window - View myDefaultView; ///< Default view - View myCurrentView; ///< Current active view - bool myStatesSaved; ///< Are we between a SaveGLStates and a RestoreGLStates? - bool myViewHasChanged; ///< Has the current view changed? + View myDefaultView; ///< Default view + View myView; ///< Current view + StatesCache myCache; ///< Render states cache }; } // namespace sf @@ -328,8 +405,8 @@ private : /// On top of that, render targets are still able to render direct /// OpenGL stuff. It is even possible to mix together OpenGL calls /// and regular SFML drawing commands. When doing so, make sure that -/// OpenGL states are not messed up by calling the SaveGLStates / -/// RestoreGLStates functions. +/// OpenGL states are not messed up by calling the +/// PushGLStates/PopGLStates functions. /// /// \see sf::RenderWindow, sf::RenderTexture, sf::View /// diff --git a/include/SFML/Graphics/RenderWindow.hpp b/include/SFML/Graphics/RenderWindow.hpp index 46ae29ef..239c2872 100644 --- a/include/SFML/Graphics/RenderWindow.hpp +++ b/include/SFML/Graphics/RenderWindow.hpp @@ -188,15 +188,14 @@ private : /// classes of the graphics module. /// /// sf::RenderWindow is derived from sf::Window, thus it inherits -/// all its features: mouse/keyboard/joystick input, events, window -/// handling, OpenGL rendering, etc. See the documentation of -/// sf::Window for a more complete description of all these features -/// and code samples. +/// all its features: events, window management, OpenGL rendering, +/// etc. See the documentation of sf::Window for a more complete +/// description of all these features, as well as code examples. /// /// On top of that, sf::RenderWindow adds more features related to /// 2D drawing with the graphics module (see its base class /// sf::RenderTarget for more details). -/// Here is a typical rendering / event loop with a sf::RenderWindow: +/// Here is a typical rendering and event loop with a sf::RenderWindow: /// /// \code /// // Declare and create a new render-window @@ -220,10 +219,10 @@ private : /// // Clear the whole window before rendering a new frame /// window.Clear(); /// -/// // Draw some sprites / shapes / texts -/// window.Draw(sprite); // sprite is a sf::Sprite -/// window.Draw(shape); // shape is a sf::Shape -/// window.Draw(text); // text is a sf::Text +/// // Draw some graphical entities +/// window.Draw(sprite); +/// window.Draw(circle); +/// window.Draw(text); /// /// // End the current frame and display its contents on screen /// window.Display(); @@ -232,9 +231,7 @@ private : /// /// Like sf::Window, sf::RenderWindow is still able to render direct /// OpenGL stuff. It is even possible to mix together OpenGL calls -/// and regular SFML drawing commands. When doing so, make sure that -/// OpenGL states are not messed up by calling the SaveGLStates / -/// RestoreGLStates functions. +/// and regular SFML drawing commands. /// /// \code /// // Create the render window @@ -256,9 +253,9 @@ private : /// ... /// /// // Draw a background sprite -/// window.SaveGLStates(); +/// window.PushGLStates(); /// window.Draw(sprite); -/// window.RestoreGLStates(); +/// window.PopGLStates(); /// /// // Draw a 3D object using OpenGL /// glBegin(GL_QUADS); @@ -267,9 +264,9 @@ private : /// glEnd(); /// /// // Draw text on top of the 3D object -/// window.SaveGLStates(); +/// window.PushGLStates(); /// window.Draw(text); -/// window.RestoreGLStates(); +/// window.PopGLStates(); /// /// // Finally, display the rendered frame on screen /// window.Display(); diff --git a/include/SFML/Graphics/Renderer.hpp b/include/SFML/Graphics/Renderer.hpp deleted file mode 100644 index 4d774c80..00000000 --- a/include/SFML/Graphics/Renderer.hpp +++ /dev/null @@ -1,363 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -#ifndef SFML_RENDERER_HPP -#define SFML_RENDERER_HPP - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include - - -namespace sf -{ -class Shader; -class Texture; - -//////////////////////////////////////////////////////////// -/// \brief Handles the low-level rendering (states and geometry) -/// -//////////////////////////////////////////////////////////// -class SFML_API Renderer : GlResource, NonCopyable -{ -public : - - //////////////////////////////////////////////////////////// - /// \brief Types of primitives to be rendererd - /// - //////////////////////////////////////////////////////////// - enum PrimitiveType - { - TriangleList, ///< Simple list of triangles - TriangleStrip, ///< Triangle strip (consecutive triangles always share two points) - TriangleFan, ///< Triangle fan (one center point + outline points) - QuadList ///< Simple list of quads - }; - -public : - - //////////////////////////////////////////////////////////// - /// \brief Construct the renderer with its owner render target - /// - /// \param target Owner render target - /// - //////////////////////////////////////////////////////////// - Renderer(RenderTarget& target); - - //////////////////////////////////////////////////////////// - /// \brief Initialize the renderer (set the default states, etc.) - /// - //////////////////////////////////////////////////////////// - void Initialize(); - - //////////////////////////////////////////////////////////// - /// \brief Save the current OpenGL render states and matrices - /// - /// \see RestoreGLStates - /// - //////////////////////////////////////////////////////////// - void SaveGLStates(); - - //////////////////////////////////////////////////////////// - /// \brief Restore the previously saved OpenGL render states and matrices - /// - /// \see SaveGLStates - /// - //////////////////////////////////////////////////////////// - void RestoreGLStates(); - - //////////////////////////////////////////////////////////// - /// Clear the color buffer - /// - /// \param color Color to use to clear the color buffer - /// - //////////////////////////////////////////////////////////// - void Clear(const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Save the current render states - /// - /// \see PopStates - /// - //////////////////////////////////////////////////////////// - void PushStates(); - - //////////////////////////////////////////////////////////// - /// \brief Restore the previously saved render states - /// - /// \see PushStates - /// - //////////////////////////////////////////////////////////// - void PopStates(); - - //////////////////////////////////////////////////////////// - /// \brief Set a new model-view matrix - /// - /// \param matrix New model-view matrix - /// - /// \see ApplyModelView - /// - //////////////////////////////////////////////////////////// - void SetModelView(const Matrix3& matrix); - - //////////////////////////////////////////////////////////// - /// \brief Combine a new model-view matrix with the current one - /// - /// \param matrix Model-view matrix to combine - /// - /// \see SetModelView - /// - //////////////////////////////////////////////////////////// - void ApplyModelView(const Matrix3& matrix); - - //////////////////////////////////////////////////////////// - /// \brief Set a new projection matrix - /// - /// \param matrix New projection matrix - /// - /// \see ApplyProjection - /// - //////////////////////////////////////////////////////////// - void SetProjection(const Matrix3& matrix); - - //////////////////////////////////////////////////////////// - /// \brief Set the current global color - /// - /// This color will be modulated with each vertex's color. - /// - /// \param color New global color - /// - /// \see ApplyColor - /// - //////////////////////////////////////////////////////////// - void SetColor(const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Modulate the current global color with a new one - /// - /// This color will be modulated with each vertex's color. - /// - /// \param color Color to modulate - /// - /// \see SetColor - /// - //////////////////////////////////////////////////////////// - void ApplyColor(const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Set the current viewport - /// - /// \param viewport New viewport to apply - /// - //////////////////////////////////////////////////////////// - void SetViewport(const IntRect& viewport); - - //////////////////////////////////////////////////////////// - /// \brief Set the current alpha-blending mode - /// - /// \param mode New blending mode - /// - //////////////////////////////////////////////////////////// - void SetBlendMode(Blend::Mode mode); - - //////////////////////////////////////////////////////////// - /// \brief Set the current texture - /// - /// \param texture New texture - /// - //////////////////////////////////////////////////////////// - void SetTexture(const Texture* texture); - - //////////////////////////////////////////////////////////// - /// \brief Set the current shader - /// - /// \param shader New Shader - /// - //////////////////////////////////////////////////////////// - void SetShader(const Shader* shader); - - //////////////////////////////////////////////////////////// - /// \brief Begin rendering a new geometry batch - /// - /// You need to call End() to complete the batch and trigger - /// the actual rendering of the geometry that you passed - /// between Begin() and End(). - /// - /// Usage: - /// \code - /// renderer.Begin(Renderer::TriangleList); - /// renderer.AddVertex(...); - /// renderer.AddVertex(...); - /// renderer.AddVertex(...); - /// renderer.End(); - /// \endcode - /// - /// \param type Type of the primitives that are going to be rendered - /// - /// \see End - /// - //////////////////////////////////////////////////////////// - void Begin(PrimitiveType type); - - //////////////////////////////////////////////////////////// - /// \brief End the current geometry batch and render it - /// - /// \see Begin - /// - //////////////////////////////////////////////////////////// - void End(); - - //////////////////////////////////////////////////////////// - /// \brief Add a new vertex (position only) - /// - /// This function adds a new vertex to the current batch. - /// This is equivalent to calling AddVertex(x, y, 0, 0, Color::White). - /// - /// \param x X coordinate of the vertex - /// \param y Y coordinate of the vertex - /// - //////////////////////////////////////////////////////////// - void AddVertex(float x, float y); - - //////////////////////////////////////////////////////////// - /// \brief Add a new vertex (position + texture coordinates) - /// - /// This function adds a new vertex to the current batch. - /// This is equivalent to calling AddVertex(x, y, u, v, Color::White). - /// - /// \param x X coordinate of the vertex - /// \param y Y coordinate of the vertex - /// \param u X texture coordinate of the vertex - /// \param v Y texture coordinate of the vertex - /// - //////////////////////////////////////////////////////////// - void AddVertex(float x, float y, float u, float v); - - //////////////////////////////////////////////////////////// - /// \brief Add a new vertex (position + color) - /// - /// This function adds a new vertex to the current batch. - /// This is equivalent to calling AddVertex(x, y, 0, 0, color). - /// - /// \param x X coordinate of the vertex - /// \param y Y coordinate of the vertex - /// \param color Color of the vertex - /// - //////////////////////////////////////////////////////////// - void AddVertex(float x, float y, const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Add a new vertex (position + texture coordinates + color) - /// - /// This function adds a new vertex to the current batch. - /// - /// \param x X coordinate of the vertex - /// \param y Y coordinate of the vertex - /// \param u X texture coordinate of the vertex - /// \param v Y texture coordinate of the vertex - /// \param color Color of the vertex - /// - //////////////////////////////////////////////////////////// - void AddVertex(float x, float y, float u, float v, const Color& color); - -private : - - //////////////////////////////////////////////////////////// - /// \brief Process a new vertex - /// - /// This function is called by all the public overloads of AddVertex, - /// it processes a new vertex to be rendered. - /// - /// \param x X coordinate of the vertex - /// \param y Y coordinate of the vertex - /// \param u X texture coordinate of the vertex - /// \param v Y texture coordinate of the vertex - /// \param r Red component of the vertex color (normalized) - /// \param g Green component of the vertex color (normalized) - /// \param b Blue component of the vertex color (normalized) - /// \param a Alpha component of the vertex color (normalized) - /// - //////////////////////////////////////////////////////////// - void ProcessVertex(float x, float y, float u, float v, float r, float g, float b, float a); - - //////////////////////////////////////////////////////////// - // Structure holding the render states that can be stacked - //////////////////////////////////////////////////////////// - struct States - { - States() : r(1.f), g(1.f), b(1.f), a(1.f) {} - - Matrix3 modelView; ///< Model-view matrix - float r, g, b, a; ///< Vertex color (normalized components for faster operations) - }; - - //////////////////////////////////////////////////////////// - // Member data - //////////////////////////////////////////////////////////// - RenderTarget& myTarget; ///< Reference to the render target owning this renderer - States myStatesStack[64]; ///< Stack of render states - States* myStates; ///< Current set of render states - const Texture* myTexture; ///< Current texture - unsigned int myTextureId; ///< Current texture identifier (the sf::Texture instance may be the same, but not the internal OpenGL texture) - const Shader* myShader; ///< Current pixel shader - Blend::Mode myBlendMode; ///< Current blending mode - IntRect myViewport; ///< Current target viewport - bool myTextureIsValid; ///< Is the cached texture valid? (if not, the cached value is ignored) - bool myShaderIsValid; ///< Is the cached shader valid? (if not, the cached value is ignored) - bool myBlendModeIsValid; ///< Is the cached blend mode valid? (if not, the cached value is ignored) - bool myViewportIsValid; ///< Is the cached viewport valid? (if not, the cached value is ignored) -}; - -} // namespace sf - - -#endif // SFML_RENDERER_HPP - - -//////////////////////////////////////////////////////////// -/// \class sf::Renderer -/// \ingroup graphics -/// -/// sf::Renderer is the abstraction layer between SFML code -/// and the low-level drawing API (OpenGL). It manages -/// render states efficiently, and provides a lightweight -/// abstraction for rendering geometry. -/// -/// The purpose of this class is to provide a single abstract -/// entry point for everything related to low-level rendering. -/// Hiding everything behind sf::Renderer makes optimizing -/// easy, as well as porting to other technologies in the future -/// (like OpenGL ES or OpenGL 3.x). -/// -/// This class is mainly meant for internal usage, you should -/// never care about it unless you write your own sf::Drawable -/// class that uses raw geometry in its Render function. -/// -//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp index 5f389ff8..07640c62 100644 --- a/include/SFML/Graphics/Shader.hpp +++ b/include/SFML/Graphics/Shader.hpp @@ -29,8 +29,10 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include +#include #include +#include #include #include #include @@ -39,32 +41,45 @@ namespace sf { -class Renderer; +class InputStream; +class Texture; //////////////////////////////////////////////////////////// -/// \brief Pixel/fragment shader class +/// \brief Shader class (vertex and fragment) /// //////////////////////////////////////////////////////////// -class SFML_API Shader : GlResource +class SFML_API Shader : GlResource, NonCopyable { +public : + + //////////////////////////////////////////////////////////// + /// \brief Types of shaders + /// + //////////////////////////////////////////////////////////// + enum Type + { + Vertex, ///< Vertex shader + Fragment ///< Fragment (pixel) shader + }; + + //////////////////////////////////////////////////////////// + /// \brief Special type/value that can be passed to SetParameter, + /// and that represents the texture of the object being drawn + /// + //////////////////////////////////////////////////////////// + struct CurrentTextureType {}; + static CurrentTextureType CurrentTexture; + public : //////////////////////////////////////////////////////////// /// \brief Default constructor /// - /// This constructor creates an invalid shader + /// This constructor creates an invalid shader. /// //////////////////////////////////////////////////////////// Shader(); - //////////////////////////////////////////////////////////// - /// \brief Copy constructor - /// - /// \param copy Instance to copy - /// - //////////////////////////////////////////////////////////// - Shader(const Shader& copy); - //////////////////////////////////////////////////////////// /// \brief Destructor /// @@ -72,64 +87,139 @@ public : ~Shader(); //////////////////////////////////////////////////////////// - /// \brief Load the shader from a file + /// \brief Load either the vertex or fragment shader from a file /// + /// This function loads a single shader, either vertex or + /// fragment, identified by the second argument. /// The source must be a text file containing a valid - /// fragment shader in GLSL language. GLSL is a C-like - /// language dedicated to OpenGL shaders; you'll probably - /// need to read a good documentation for it before writing - /// your own shaders. + /// shader in GLSL language. GLSL is a C-like language + /// dedicated to OpenGL shaders; you'll probably need to + /// read a good documentation for it before writing your + /// own shaders. /// - /// \param filename Path of the shader file to load + /// \param filename Path of the vertex or fragment shader file to load + /// \param type Type of shader (vertex or fragment) /// /// \return True if loading succeeded, false if it failed /// /// \see LoadFromMemory, LoadFromStream /// //////////////////////////////////////////////////////////// - bool LoadFromFile(const std::string& filename); + bool LoadFromFile(const std::string& filename, Type type); //////////////////////////////////////////////////////////// - /// \brief Load the shader from a source code in memory + /// \brief Load both the vertex and fragment shaders from files /// - /// The source code must be a valid fragment shader in - /// GLSL language. GLSL is a C-like language dedicated - /// to OpenGL shaders; you'll probably need to read a - /// good documentation for it before writing your own shaders. + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be text files containing valid shaders + /// in GLSL language. GLSL is a C-like language dedicated to + /// OpenGL shaders; you'll probably need to read a good documentation + /// for it before writing your own shaders. + /// + /// \param vertexShaderFilename Path of the vertex shader file to load + /// \param fragmentShaderFilename Path of the fragment shader file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see LoadFromMemory, LoadFromStream + /// + //////////////////////////////////////////////////////////// + bool LoadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename); + + //////////////////////////////////////////////////////////// + /// \brief Load either the vertex or fragment shader from a source code in memory + /// + /// This function loads a single shader, either vertex or + /// fragment, identified by the second argument. + /// The source code must be a valid shader in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. /// /// \param shader String containing the source code of the shader + /// \param type Type of shader (vertex or fragment) /// /// \return True if loading succeeded, false if it failed /// /// \see LoadFromFile, LoadFromStream /// //////////////////////////////////////////////////////////// - bool LoadFromMemory(const std::string& shader); + bool LoadFromMemory(const std::string& shader, Type type); //////////////////////////////////////////////////////////// - /// \brief Load the shader from a custom stream + /// \brief Load both the vertex and fragment shaders from source codes in memory /// - /// The source code must be a valid fragment shader in - /// GLSL language. GLSL is a C-like language dedicated - /// to OpenGL shaders; you'll probably need to read a - /// good documentation for it before writing your own shaders. + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be valid shaders in GLSL language. GLSL is + /// a C-like language dedicated to OpenGL shaders; you'll + /// probably need to read a good documentation for it before + /// writing your own shaders. + /// + /// \param vertexShader String containing the source code of the vertex shader + /// \param fragmentShader String containing the source code of the fragment shader + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see LoadFromFile, LoadFromStream + /// + //////////////////////////////////////////////////////////// + bool LoadFromMemory(const std::string& vertexShader, const std::string& fragmentShader); + + //////////////////////////////////////////////////////////// + /// \brief Load either the vertex or fragment shader from a custom stream + /// + /// This function loads a single shader, either vertex or + /// fragment, identified by the second argument. + /// The source code must be a valid shader in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for it + /// before writing your own shaders. /// /// \param stream Source stream to read from + /// \param type Type of shader (vertex or fragment) /// /// \return True if loading succeeded, false if it failed /// /// \see LoadFromFile, LoadFromMemory /// //////////////////////////////////////////////////////////// - bool LoadFromStream(InputStream& stream); + bool LoadFromStream(InputStream& stream, Type type); + + //////////////////////////////////////////////////////////// + /// \brief Load both the vertex and fragment shaders from custom streams + /// + /// This function loads both the vertex and the fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The source codes must be valid shaders in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. + /// + /// \param vertexShaderStream Source stream to read the vertex shader from + /// \param fragmentShaderStream Source stream to read the fragment shader from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see LoadFromFile, LoadFromMemory + /// + //////////////////////////////////////////////////////////// + bool LoadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream); //////////////////////////////////////////////////////////// /// \brief Change a float parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a float + /// (float GLSL type). + /// + /// Example: /// \code - /// uniform float myparam; // this is the variable in the pixel shader + /// uniform float myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", 5.2f); @@ -138,8 +228,6 @@ public : /// \param name Name of the parameter in the shader /// \param x Value to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x); @@ -147,9 +235,12 @@ public : /// \brief Change a 2-components vector parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a 2x1 vector + /// (vec2 GLSL type). + /// + /// Example: /// \code - /// uniform vec2 myparam; // this is the variable in the pixel shader + /// uniform vec2 myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", 5.2f, 6.0f); @@ -159,8 +250,6 @@ public : /// \param x First component of the value to assign /// \param y Second component of the value to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y); @@ -168,9 +257,12 @@ public : /// \brief Change a 3-components vector parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a 3x1 vector + /// (vec3 GLSL type). + /// + /// Example: /// \code - /// uniform vec3 myparam; // this is the variable in the pixel shader + /// uniform vec3 myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", 5.2f, 6.0f, -8.1f); @@ -181,8 +273,6 @@ public : /// \param y Second component of the value to assign /// \param z Third component of the value to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y, float z); @@ -190,9 +280,12 @@ public : /// \brief Change a 4-components vector parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a 4x1 vector + /// (vec4 GLSL type). + /// + /// Example: /// \code - /// uniform vec4 myparam; // this is the variable in the pixel shader + /// uniform vec4 myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", 5.2f, 6.0f, -8.1f, 0.4f); @@ -204,8 +297,6 @@ public : /// \param z Third component of the value to assign /// \param w Fourth component of the value to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y, float z, float w); @@ -213,9 +304,12 @@ public : /// \brief Change a 2-components vector parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a 2x1 vector + /// (vec2 GLSL type). + /// + /// Example: /// \code - /// uniform vec2 myparam; // this is the variable in the pixel shader + /// uniform vec2 myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", sf::Vector2f(5.2f, 6.0f)); @@ -224,8 +318,6 @@ public : /// \param name Name of the parameter in the shader /// \param vector Vector to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, const Vector2f& vector); @@ -233,9 +325,12 @@ public : /// \brief Change a 2-components vector parameter of the shader /// /// \a name is the name of the variable to change in the shader. - /// For example: + /// The corresponding parameter in the shader must be a 3x1 vector + /// (vec3 GLSL type). + /// + /// Example: /// \code - /// uniform vec3 myparam; // this is the variable in the pixel shader + /// uniform vec3 myparam; // this is the variable in the shader /// \endcode /// \code /// shader.SetParameter("myparam", sf::Vector3f(5.2f, 6.0f, -8.1f)); @@ -244,59 +339,113 @@ public : /// \param name Name of the parameter in the shader /// \param vector Vector to assign /// - /// \see SetTexture, SetCurrentTexture - /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, const Vector3f& vector); //////////////////////////////////////////////////////////// - /// \brief Change a texture parameter of the shader + /// \brief Change a color parameter of the shader + /// + /// \a name is the name of the variable to change in the shader. + /// The corresponding parameter in the shader must be a 4x1 vector + /// (vec4 GLSL type). + /// + /// It is important to note that the components of the color are + /// normalized before being passed to the shader. Therefore, + /// they are converted from range [0 .. 255] to range [0 .. 1]. + /// For example, a sf::Color(255, 125, 0, 255) will be transformed + /// to a vec4(1.0, 0.5, 0.0, 1.0) in the shader. /// - /// \a name is the name of the texture to change in the shader. - /// This function maps an external texture to the given shader - /// variable; to use the current texture of the object being drawn, - /// use SetCurrentTexture instead. /// Example: /// \code - /// // These are the variables in the pixel shader - /// uniform sampler2D the_texture; + /// uniform vec4 color; // this is the variable in the shader + /// \endcode + /// \code + /// shader.SetParameter("color", sf::Color(255, 128, 0, 255)); + /// \endcode + /// + /// \param name Name of the parameter in the shader + /// \param color Color to assign + /// + //////////////////////////////////////////////////////////// + void SetParameter(const std::string& name, const Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Change a matrix parameter of the shader + /// + /// \a name is the name of the variable to change in the shader. + /// The corresponding parameter in the shader must be a 4x4 matrix + /// (mat4 GLSL type). + /// + /// Example: + /// \code + /// uniform mat4 matrix; // this is the variable in the shader + /// \endcode + /// \code + /// sf::Transform transform; + /// transform.Translate(5, 10); + /// shader.SetParameter("matrix", transform); + /// \endcode + /// + /// \param name Name of the parameter in the shader + /// \param transform Transform to assign + /// + //////////////////////////////////////////////////////////// + void SetParameter(const std::string& name, const sf::Transform& transform); + + //////////////////////////////////////////////////////////// + /// \brief Change a texture parameter of the shader + /// + /// \a name is the name of the variable to change in the shader. + /// The corresponding parameter in the shader must be a 2D texture + /// (sampler2D GLSL type). + /// + /// Example: + /// \code + /// uniform sampler2D the_texture; // this is the variable in the shader /// \endcode /// \code /// sf::Texture texture; /// ... - /// shader.SetTexture("the_texture", texture); + /// shader.SetParameter("the_texture", texture); /// \endcode /// It is important to note that \a texture must remain alive as long /// as the shader uses it, no copy is made internally. /// + /// To use the texture of the object being draw, which cannot be + /// known in advance, you can pass the special value + /// sf::Shader::CurrentTexture: + /// \code + /// shader.SetParameter("the_texture", sf::Shader::CurrentTexture). + /// \endcode + /// /// \param name Name of the texture in the shader /// \param texture Texture to assign /// - /// \see SetParameter, SetCurrentTexture - /// //////////////////////////////////////////////////////////// - void SetTexture(const std::string& name, const Texture& texture); + void SetParameter(const std::string& name, const Texture& texture); //////////////////////////////////////////////////////////// - /// \brief Set the current object texture in the shader + /// \brief Change a texture parameter of the shader + /// + /// This overload maps a shader texture variable to the + /// texture of the object being drawn, which cannot be + /// known in advance. The second argument must be + /// sf::Shader::CurrentTexture. + /// The corresponding parameter in the shader must be a 2D texture + /// (sampler2D GLSL type). /// - /// This function maps a shader texture variable to the - /// texture of the object being drawn. /// Example: /// \code - /// // This is the variable in the pixel shader - /// uniform sampler2D current; + /// uniform sampler2D current; // this is the variable in the shader /// \endcode /// \code - /// shader.SetCurrentTexture("current"); + /// shader.SetParameter("current", sf::Shader::CurrentTexture); /// \endcode /// /// \param name Name of the texture in the shader /// - /// \see SetParameter, SetTexture - /// //////////////////////////////////////////////////////////// - void SetCurrentTexture(const std::string& name); + void SetParameter(const std::string& name, CurrentTextureType); //////////////////////////////////////////////////////////// /// \brief Bind the shader for rendering (activate it) @@ -328,16 +477,6 @@ public : //////////////////////////////////////////////////////////// void Unbind() const; - //////////////////////////////////////////////////////////// - /// \brief Overload of assignment operator - /// - /// \param right Instance to assign - /// - /// \return Reference to self - /// - //////////////////////////////////////////////////////////// - Shader& operator =(const Shader& right); - //////////////////////////////////////////////////////////// /// \brief Tell whether or not the system supports shaders /// @@ -352,15 +491,19 @@ public : private : - friend class Renderer; - //////////////////////////////////////////////////////////// - /// \brief Create the program and attach the shaders + /// \brief Compile the shader(s) and create the program + /// + /// If one of the arguments is NULL, the corresponding shader + /// is not created. + /// + /// \param vertexShaderCode Source code of the vertex shader + /// \param fragmentShaderCode Source code of the fragment shader /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - bool CompileProgram(); + bool CompileProgram(const char* vertexShaderCode, const char* fragmentShaderCode); //////////////////////////////////////////////////////////// /// \brief Bind all the textures used by the shader @@ -371,16 +514,6 @@ private : //////////////////////////////////////////////////////////// void BindTextures() const; - //////////////////////////////////////////////////////////// - /// \brief Make sure that the shader is ready to be used - /// - /// This function is called by the Renderer class, to make - /// sure that the shader's parameters are properly applied - /// even when Use() is not called due to internal optimizations. - /// - //////////////////////////////////////////////////////////// - void Use() const; - //////////////////////////////////////////////////////////// // Types //////////////////////////////////////////////////////////// @@ -392,7 +525,6 @@ private : unsigned int myShaderProgram; ///< OpenGL identifier for the program int myCurrentTexture; ///< Location of the current texture in the shader TextureTable myTextures; ///< Texture variables in the shader, mapped to their location - std::string myFragmentShader; ///< Fragment shader source code }; } // namespace sf @@ -405,34 +537,44 @@ private : /// \class sf::Shader /// \ingroup graphics /// -/// Pixel shaders (or fragment shaders) are programs written -/// using a specific language, executed directly by the -/// graphics card and allowing to apply per-pixel real-time -/// operations to the rendered entities. +/// Shaders are programs written using a specific language, +/// executed directly by the graphics card and allowing +/// to apply real-time operations to the rendered entities. /// -/// Pixel shaders are written in GLSL, which is a C-like +/// There are two kinds of shaders: +/// \li Vertex shaders, that process vertices +/// \li Fragment (pixel) shaders, that process pixels +/// +/// A sf::Shader can be composed of either a vertex shader +/// alone, a fragment shader alone, or both combined +/// (see the variants of the Load functions). +/// +/// Shaders are written in GLSL, which is a C-like /// language dedicated to OpenGL shaders. You'll probably /// need to learn its basics before writing your own shaders /// for SFML. /// /// Like any C/C++ program, a shader has its own variables /// that you can set from your C++ application. sf::Shader -/// handles 3 different types of variables: +/// handles 4 different types of variables: /// \li floats /// \li vectors (2, 3 or 4 components) /// \li textures +/// \li transforms (matrices) /// /// The value of the variables can be changed at any time -/// with either Shader::SetParameter or Shader::SetTexture: +/// with either the various overloads of the SetParameter function: /// \code /// shader.SetParameter("offset", 2.f); /// shader.SetParameter("color", 0.5f, 0.8f, 0.3f); -/// shader.SetTexture("overlay", texture); // texture is a sf::Texture -/// shader.SetCurrentTexture("texture"); +/// shader.SetParameter("matrix", transform); // transform is a sf::Transform +/// shader.SetParameter("overlay", texture); // texture is a sf::Texture +/// shader.SetParameter("texture", sf::Shader::CurrentTexture); /// \endcode /// -/// Shader::SetCurrentTexture maps the given texture variable -/// to the current texture of the object being drawn. +/// The special Shader::CurrentTexture argument maps the +/// given texture variable to the current texture of the +/// object being drawn (which cannot be known in advance). /// /// To apply a shader to a drawable, you must pass it as an /// additional parameter to the Draw function: @@ -440,15 +582,22 @@ private : /// window.Draw(sprite, shader); /// \endcode /// -/// Shaders can be used on any drawable, but they are mainly -/// made for sf::Sprite. Using a shader on a sf::String is more -/// limited, because the texture of the text is not the -/// actual text that you see on screen, it is a big texture -/// containing all the characters of the font in an arbitrary -/// order. Thus, texture lookups on pixels other than the current -/// one may not give you the expected result. Using a shader -/// with sf::Shape is even more limited, as shapes don't use -/// any texture. +/// ... which is in fact just a shortcut for this: +/// \code +/// sf::RenderStates states; +/// states.Shader = shader; +/// window.Draw(sprite, states); +/// \endcode +/// +/// Shaders can be used on any drawable, but some combinations are +/// not interesting. For example, using a vertex shader on a sf::Sprite +/// is limited because there are only 4 vertices, the sprite would +/// have to be subdivided in order to apply wave effects. +/// Another bad example is a fragment shader with sf::Text: the texture +/// of the text is not the actual text that you see on screen, it is +/// a big texture containing all the characters of the font in an +/// arbitrary order; thus, texture lookups on pixels other than the +/// current one may not give you the expected result. /// /// Shaders can also be used to apply global post-effects to the /// current contents of the target (like the old sf::PostFx class @@ -462,11 +611,11 @@ private : /// The first technique is more optimized because it doesn't involve /// retrieving the target's pixels to system memory, but the /// second one doesn't impact the rendering process and can be -/// easily inserted anywhere. +/// easily inserted anywhere without impacting all the code. /// /// Like sf::Texture that can be used as a raw OpenGL texture, -/// sf::Shader can also be used directly as a raw fragment -/// shader for custom OpenGL geometry. +/// sf::Shader can also be used directly as a raw shader for +/// custom OpenGL geometry. /// \code /// window.SetActive(); /// shader.Bind(); diff --git a/include/SFML/Graphics/Shape.hpp b/include/SFML/Graphics/Shape.hpp index a183539a..1b545b41 100644 --- a/include/SFML/Graphics/Shape.hpp +++ b/include/SFML/Graphics/Shape.hpp @@ -29,208 +29,155 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include #include -#include namespace sf { //////////////////////////////////////////////////////////// -/// \brief A convex, colored polygon with an optional outline +/// \brief Base class for textured shapes with outline /// //////////////////////////////////////////////////////////// -class SFML_API Shape : public Drawable +class SFML_API Shape : public Drawable, public Transformable { public : //////////////////////////////////////////////////////////// - /// \brief Default constructor - /// - /// Creates an empty shape (no point). + /// \brief Virtual destructor /// //////////////////////////////////////////////////////////// - Shape(); + virtual ~Shape(); //////////////////////////////////////////////////////////// - /// \brief Add a new point to the shape + /// \brief Change the source texture of the shape /// - /// The new point is inserted at the end of the shape. + /// The \a texture argument refers to a texture that must + /// exist as long as the shape uses it. Indeed, the shape + /// doesn't store its own copy of the texture, but rather keeps + /// a pointer to the one that you passed to this function. + /// If the source texture is destroyed and the shape tries to + /// use it, the behaviour is undefined. + /// \a texture can be NULL to disable texturing. + /// If \a resetRect is true, the TextureRect property of + /// the shape is automatically adjusted to the size of the new + /// texture. If it is false, the texture rect is left unchanged. /// - /// \param x X position of the point - /// \param y Y position of the point - /// \param color Color of the point - /// \param outlineColor Outline color of the point + /// \param texture New texture + /// \param resetRect Should the texture rect be reset to the size of the new texture? + /// + /// \see GetTexture, SetTextureRect /// //////////////////////////////////////////////////////////// - void AddPoint(float x, float y, const Color& color = Color(255, 255, 255), const Color& outlineColor = Color(0, 0, 0)); + void SetTexture(const Texture* texture, bool resetRect = false); //////////////////////////////////////////////////////////// - /// \brief Add a new point to the shape + /// \brief Set the sub-rectangle of the texture that the shape will display /// - /// The new point is inserted at the end of the shape. + /// The texture rect is useful when you don't want to display + /// the whole texture, but rather a part of it. + /// By default, the texture rect covers the entire texture. /// - /// \param position Position of the point - /// \param color Color of the point - /// \param outlineColor Outline color of the point + /// \param rect Rectangle defining the region of the texture to display + /// + /// \see GetTextureRect, SetTexture /// //////////////////////////////////////////////////////////// - void AddPoint(const Vector2f& position, const Color& color = Color(255, 255, 255), const Color& outlineColor = Color(0, 0, 0)); + void SetTextureRect(const IntRect& rect); //////////////////////////////////////////////////////////// - /// \brief Get the number of points composing the shape + /// \brief Set the fill color of the shape /// - /// \return Total number of points + /// This color is modulated (multiplied) with the shape's + /// texture if any. It can be used to colorize the shape, + /// or change its global opacity. + /// You can use sf::Color::Transparent to make the inside of + /// the shape transparent, and have the outline alone. + /// By default, the shape's fill color is opaque white. + /// + /// \param color New color of the shape + /// + /// \see GetFillColor, SetOutlineColor /// //////////////////////////////////////////////////////////// - unsigned int GetPointsCount() const; + void SetFillColor(const Color& color); //////////////////////////////////////////////////////////// - /// \brief Enable or disable the shape's filling + /// \brief Set the outline color of the shape /// - /// This option is enabled by default. + /// You can use sf::Color::Transparent to disable the outline. + /// By default, the shape's outline color is opaque white. /// - /// \param enable True to enable, false to disable + /// \param color New outline color of the shape /// - /// \see EnableOutline + /// \see GetOutlineColor, SetFillColor /// //////////////////////////////////////////////////////////// - void EnableFill(bool enable); + void SetOutlineColor(const Color& color); //////////////////////////////////////////////////////////// - /// \brief Enable or disable the shape's outline + /// \brief Set the thickness of the shape's outline /// - /// This option is enabled by default. + /// This number cannot be negative. Using zero disables + /// the outline. + /// By default, the outline thickness is 0. /// - /// \param enable True to enable, false to disable + /// \param thickness New outline thickness /// - /// \see EnableFill - /// - //////////////////////////////////////////////////////////// - void EnableOutline(bool enable); - - //////////////////////////////////////////////////////////// - /// \brief Change the position of a point - /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. - /// - /// \param index Index of the point - /// \param position New position of the point - /// - /// \see GetPointPosition, SetPointColor, SetPointOutlineColor - /// - //////////////////////////////////////////////////////////// - void SetPointPosition(unsigned int index, const Vector2f& position); - - //////////////////////////////////////////////////////////// - /// \brief Change the position of a point - /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. - /// - /// \param index Index of the point - /// \param x New X coordinate of the point - /// \param y New Y coordinate of the point - /// - /// \see GetPointPosition, SetPointColor, SetPointOutlineColor - /// - //////////////////////////////////////////////////////////// - void SetPointPosition(unsigned int index, float x, float y); - - //////////////////////////////////////////////////////////// - /// \brief Change the color of a point - /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. - /// - /// \param index Index of the point - /// \param color New color of the point - /// - /// \see GetPointColor, SetPointPosition, SetPointOutlineColor - /// - //////////////////////////////////////////////////////////// - void SetPointColor(unsigned int index, const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Change the outline color of a point - /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. - /// - /// \param index Index of the point - /// \param color New outline color of the point - /// - /// \see GetPointOutlineColor, SetPointPosition, SetPointColor - /// - //////////////////////////////////////////////////////////// - void SetPointOutlineColor(unsigned int index, const Color& color); - - //////////////////////////////////////////////////////////// - /// \brief Change the thickness of the shape outline - /// - /// \param thickness New thickness of the outline - /// - /// \see GetOutlineThickness, EnableOutline + /// \see GetOutlineThickness /// //////////////////////////////////////////////////////////// void SetOutlineThickness(float thickness); //////////////////////////////////////////////////////////// - /// \brief Get the position of a point + /// \brief Get the source texture of the shape /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. + /// If the shape has no source texture, a NULL pointer is returned. + /// The returned pointer is const, which means that you can't + /// modify the texture when you retrieve it with this function. /// - /// \param index Index of the point + /// \return Pointer to the shape's texture /// - /// \return Position of the index-th point - /// - /// \see SetPointPosition, GetPointColor, GetPointOutlineColor + /// \see SetTexture /// //////////////////////////////////////////////////////////// - const Vector2f& GetPointPosition(unsigned int index) const; + const Texture* GetTexture() const; //////////////////////////////////////////////////////////// - /// \brief Get the color of a point + /// \brief Get the sub-rectangle of the texture displayed by the shape /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. + /// \return Texture rectangle of the shape /// - /// \param index Index of the point - /// - /// \return Color of the index-th point - /// - /// \see SetPointColor, GetPointPosition, GetPointOutlineColor + /// \see SetTextureRect /// //////////////////////////////////////////////////////////// - const Color& GetPointColor(unsigned int index) const; + const IntRect& GetTextureRect() const; //////////////////////////////////////////////////////////// - /// \brief Get the outline color of a point + /// \brief Get the fill color of the shape /// - /// Warning: this function doesn't check the validity of - /// \a index, if it is out of bounds (ie. in the range - /// [0, GetPointscount() - 1]) the behaviour is undefined. + /// \return Fill color of the shape /// - /// \param index Index of the point - /// - /// \return Outline color of the index-th point - /// - /// \see SetPointOutlineColor, GetPointPosition, GetPointColor + /// \see SetFillColor /// //////////////////////////////////////////////////////////// - const Color& GetPointOutlineColor(unsigned int index) const; + const Color& GetFillColor() const; //////////////////////////////////////////////////////////// - /// \brief Get the thickness of the shape outline + /// \brief Get the outline color of the shape /// - /// \return Current outline thickness + /// \return Outline color of the shape + /// + /// \see SetOutlineColor + /// + //////////////////////////////////////////////////////////// + const Color& GetOutlineColor() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the outline thickness of the shape + /// + /// \return Outline thickness of the shape /// /// \see SetOutlineThickness /// @@ -238,221 +185,118 @@ public : float GetOutlineThickness() const; //////////////////////////////////////////////////////////// - /// \brief Create a new line + /// \brief Get the total number of points of the shape /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::Shape line = sf::Shape::Line(0, 0, 10, 20, 2.5f, sf::Color::Green); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. - /// - /// \param p1x X coordinate of the start point - /// \param p1y Y coordinate of the start point - /// \param p2x X coordinate of the end point - /// \param p2y Y coordinate of the end point - /// \param thickness Thickness of the line - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Rectangle, Circle + /// \return Number of points of the shape /// //////////////////////////////////////////////////////////// - static Shape Line(float p1x, float p1y, float p2x, float p2y, float thickness, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); + virtual unsigned int GetPointsCount() const = 0; //////////////////////////////////////////////////////////// - /// \brief Create a new line + /// \brief Get a point of the shape /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::Vector2f start(0, 0); - /// sf::Vector2f end(10, 20); - /// sf::Shape line = sf::Shape::Line(start, end, 2.5f, sf::Color::Green); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. + /// \param index Index of the point to get, in range [0 .. GetPointsCount() - 1] /// - /// \param start Start point - /// \param end End point - /// \param thickness Thickness of the line - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Rectangle, Circle + /// \return Index-th point of the shape /// //////////////////////////////////////////////////////////// - static Shape Line(const Vector2f& start, const Vector2f& end, float thickness, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); + virtual Vector2f GetPoint(unsigned int index) const = 0; //////////////////////////////////////////////////////////// - /// \brief Create a new rectangular shape + /// \brief Get the local bounding rectangle of the entity /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::Shape rect = sf::Shape::Rectangle(10, 20, 50, 100, sf::Color::Red); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. /// - /// \param left Left coordinate of the rectangle - /// \param top Top coordinate of the rectangle - /// \param width Width of the rectangle - /// \param height Height of the rectangle - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Line, Circle + /// \return Local bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - static Shape Rectangle(float left, float top, float width, float height, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); + FloatRect GetLocalBounds() const; //////////////////////////////////////////////////////////// - /// \brief Create a new rectangular shape + /// \brief Get the global bounding rectangle of the entity /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::FloatRect source(10, 20, 50, 100); - /// sf::Shape rect = sf::Shape::Rectangle(source, sf::Color::Red); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. + /// The returned rectangle is in global coordinates, which means + /// that it takes in account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// sprite in the global 2D world's coordinate system. /// - /// \param rectangle Rectangle defining the shape - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Line, Circle + /// \return Global bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - static Shape Rectangle(const FloatRect& rectangle, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); - - //////////////////////////////////////////////////////////// - /// \brief Create a new circular shape - /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::Shape circle = sf::Shape::Circle(0, 0, 7, sf::Color::Blue); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. - /// - /// \param x X coordinate of the center - /// \param y Y coordinate of the center - /// \param radius Radius of the circle - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Line, Rectangle - /// - //////////////////////////////////////////////////////////// - static Shape Circle(float x, float y, float radius, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); - - //////////////////////////////////////////////////////////// - /// \brief Create a new circular shape - /// - /// This is a static function that returns a new object, - /// don't try to call it on an existing object to modify it. - /// \code - /// sf::Vector2f center(0, 0); - /// sf::Shape circle = sf::Shape::Circle(center, 7, sf::Color::Blue); - /// \endcode - /// Warning: the position and color that you pass to this function - /// are used to compute the position and color of each point, - /// they have nothing to do with the global position and color - /// of the shape, inherited from sf::Drawable. - /// See the class description for more information about this. - /// - /// \param center Center of the circle - /// \param radius Radius of the circle - /// \param color Color of the shape's points - /// \param outline Outline thickness - /// \param outlineColor Outline color of the shape's points - /// - /// \see Line, Rectangle - /// - //////////////////////////////////////////////////////////// - static Shape Circle(const Vector2f& center, float radius, const Color& color, float outline = 0.f, const Color& outlineColor = Color(0, 0, 0)); + FloatRect GetGlobalBounds() const; protected : //////////////////////////////////////////////////////////// - /// \brief Draw the object to a render target - /// - /// \param target Render target - /// \param renderer Renderer providing low-level rendering commands + /// \brief Default constructor /// //////////////////////////////////////////////////////////// - virtual void Render(RenderTarget& target, Renderer& renderer) const; + Shape(); + + //////////////////////////////////////////////////////////// + /// \brief Recompute the internal geometry of the shape + /// + /// This function must be called by the derived class everytime + /// the shape's points change (ie. the result of either + /// GetPointsCount or GetPoint is different). + /// + //////////////////////////////////////////////////////////// + void Update(); private : //////////////////////////////////////////////////////////// - /// \brief Compile the shape + /// \brief Draw the shape to a render target /// - /// This function precomputes all the internal parameters - /// needed to properly render the shape (center, outline points). + /// \param target Render target to draw to + /// \param states Current render states /// //////////////////////////////////////////////////////////// - void Compile(); + virtual void Draw(RenderTarget& target, RenderStates states) const; //////////////////////////////////////////////////////////// - /// \brief Compute the normal of a given 2D segment - /// - /// \param p1 First point of the segment - /// \param p2 Second point of the segment - /// \param normal Variable to fill with the calculated normal - /// - /// \return False if the normal couldn't be calculated (segment is null) + /// \brief Update the fill vertices' color /// //////////////////////////////////////////////////////////// - static bool ComputeNormal(const Vector2f& p1, const Vector2f& p2, Vector2f& normal); + void UpdateFillColors(); //////////////////////////////////////////////////////////// - /// \brief Define a simple 2D point with position, normal and colors + /// \brief Update the fill vertices' texture coordinates /// //////////////////////////////////////////////////////////// - struct Point - { - Point(const Vector2f& position = Vector2f(0, 0), const Color& color = Color(255, 255, 255), const Color& outlineColor = Color(255, 255, 255)); + void UpdateTexCoords(); - Vector2f Position; ///< Position - Vector2f Normal; ///< Extruded normal - Color Col; ///< Color of the point - Color OutlineCol; ///< Outline color of the point - }; + //////////////////////////////////////////////////////////// + /// \brief Update the outline vertices' position + /// + //////////////////////////////////////////////////////////// + void UpdateOutline(); + + //////////////////////////////////////////////////////////// + /// \brief Update the outline vertices' color + /// + //////////////////////////////////////////////////////////// + void UpdateOutlineColors(); + +private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - std::vector myPoints; ///< Points composing the shape - float myOutline; ///< Outline thickness - bool myIsFillEnabled; ///< Should we draw the inside if the shape ? - bool myIsOutlineEnabled; ///< Should we draw the outline if the shape ? - bool myIsCompiled; ///< Compiled state of the shape + const Texture* myTexture; ///< Texture of the shape + IntRect myTextureRect; ///< Rectangle defining the area of the source texture to display + Color myFillColor; ///< Fill color + Color myOutlineColor; ///< Outline color + float myOutlineThickness; ///< Thickness of the shape's outline + VertexArray myVertices; ///< Vertex array containing the fill geometry + VertexArray myOutlineVertices; ///< Vertex array containing the outline geometry + FloatRect myInsideBounds; ///< Bounding rectangle of the inside (fill) + FloatRect myBounds; ///< Bounding rectangle of the whole shape (outline + fill) }; } // namespace sf @@ -467,73 +311,28 @@ private : /// /// sf::Shape is a drawable class that allows to define and /// display a custom convex shape on a render target. +/// It's only an abstract base, it needs to be specialized for +/// concrete types of shapes (circle, rectangle, convex polygon, +/// star, ...). /// -/// It is important to keep in mind that shapes must always be -/// convex, otherwise they may not be drawn correctly. Moreover, -/// the points must be added in the right order; using a random -/// order would also result in an incorrect shape. +/// In addition to the attributes provided by the specialized +/// shape classes, a shape always has the following attributes: +/// \li a texture +/// \li a texture rectangle +/// \li a fill color +/// \li an outline color +/// \li an outline thickness /// -/// A shape is made of points that have their own individual -/// attributes: -/// \li position (relative to the origin of the shape) -/// \li color -/// \li outline color +/// Each feature is optional, and can be disabled easily: +/// \li the texture can be null +/// \li the fill/outline colors can be sf::Color::Transparent +/// \li the outline thickness can be zero /// -/// Shapes have an outline that can be enabled or not. You can -/// control the thickness of the outline with the SetOutlineThickness -/// function. +/// You can write your own derived shape class, there are only +/// two virtual functions to override: +/// \li GetOutlinePointsCount must return the number of points of the shape +/// \li GetOutlinePoint must return the points of the shape /// -/// They also inherits all the functions from sf::Drawable: -/// position, rotation, scale, origin, global color and blend -/// mode. -/// -/// Some static functions are provided to directly create common -/// shapes such as lines, rectangles and circles: -/// \code -/// sf::Shape line = sf::Shape::Line(start, end, thickness, color); -/// sf::Shape rectangle = sf::Shape::Rectangle(rect, thickness); -/// sf::Shape circle = sf::Shape::Circle(center, radius, color); -/// \endcode -/// -/// A common mistake is to mix the individual points -/// positions / colors and the global position / color of the shape. -/// They are completely separate attributes that are combined -/// when the shape is drawn (positions are added, colors are multiplied). -/// \code -/// sf::Shape line = sf::Shape::Line(sf::Vector2f(100, 100), sf::Vector2f(200, 200), 10, sf::Color::Red); -/// -/// // --> line.GetPosition() is (0, 0), *not* (100, 100) -/// // --> line.GetColor() is white, *not* red -/// \endcode -/// So if you plan to change the position / color of your shape -/// after it is created, you'd better create the points around -/// the origin and with white color, and use only the global -/// position / color (SetPosition, SetColor). -/// -/// Usage example: -/// \code -/// // Create a shape -/// sf::Shape shape; -/// -/// // Define its points -/// shape.AddPoint(10, 10, sf::Color::White, sf::Color::Red); -/// shape.AddPoint(50, 10, sf::Color::White, sf::Color::Green); -/// shape.AddPoint(10, 50, sf::Color::White, sf::Color::Blue); -/// -/// // Enable outline only -/// shape.EnableFill(false); -/// shape.EnableOutline(true); -/// shape.SetOutlineThickness(10); -/// -/// // Display it -/// window.Draw(shape); // window is a sf::RenderWindow -/// -/// // Display static shapes -/// window.Draw(sf::Shape::Line(0, 0, 10, 20, sf::Color::Red)); -/// window.Draw(sf::Shape::Rectangle(100, 1000, 50, 20, sf::Color::Green)); -/// window.Draw(sf::Shape::Circle(500, 500, 20, sf::Color::Blue, 5, sf::Color::Black)); -/// \endcode -/// -/// \see sf::Sprite +/// \see sf::LineShape, sf::RectangleShape, sf::CircleShape, sf::ConvexShape, sf::Transformable /// //////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Sprite.hpp b/include/SFML/Graphics/Sprite.hpp index 38af302a..675a920f 100644 --- a/include/SFML/Graphics/Sprite.hpp +++ b/include/SFML/Graphics/Sprite.hpp @@ -29,6 +29,8 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include #include @@ -38,10 +40,10 @@ class Texture; //////////////////////////////////////////////////////////// /// \brief Drawable representation of a texture, with its -/// own transformations, color, blend mode, etc. +/// own transformations, color, etc. /// //////////////////////////////////////////////////////////// -class SFML_API Sprite : public Drawable +class SFML_API Sprite : public Drawable, public Transformable { public : @@ -56,11 +58,24 @@ public : //////////////////////////////////////////////////////////// /// \brief Construct the sprite from a source texture /// + /// \param texture Source texture + /// /// \see SetTexture /// //////////////////////////////////////////////////////////// explicit Sprite(const Texture& texture); + //////////////////////////////////////////////////////////// + /// \brief Construct the sprite from a sub-rectangle of a source texture + /// + /// \param texture Source texture + /// \param rectangle Sub-rectangle of the texture to assign to the sprite + /// + /// \see SetTexture, SetTextureRect + /// + //////////////////////////////////////////////////////////// + Sprite(const Texture& texture, const IntRect& rectangle); + //////////////////////////////////////////////////////////// /// \brief Change the source texture of the sprite /// @@ -69,91 +84,52 @@ public : /// doesn't store its own copy of the texture, but rather keeps /// a pointer to the one that you passed to this function. /// If the source texture is destroyed and the sprite tries to - /// use it, it may appear as a white rectangle. - /// If \a adjustToNewSize is true, the SubRect property of - /// the sprite is adjusted to the size of the new texture. If - /// it is false, the SubRect is unchanged. + /// use it, the behaviour is undefined. + /// If \a resetRect is true, the TextureRect property of + /// the sprite is automatically adjusted to the size of the new + /// texture. If it is false, the texture rect is left unchanged. /// - /// \param texture New texture - /// \param adjustToNewSize Should the sub-rect be adjusted to the size of the new texture? + /// \param texture New texture + /// \param resetRect Should the texture rect be reset to the size of the new texture? /// - /// \see GetTexture, SetSubRect + /// \see GetTexture, SetTextureRect /// //////////////////////////////////////////////////////////// - void SetTexture(const Texture& texture, bool adjustToNewSize = false); + void SetTexture(const Texture& texture, bool resetRect = false); //////////////////////////////////////////////////////////// - /// \brief Set the part of the texture that the sprite will display + /// \brief Set the sub-rectangle of the texture that the sprite will display /// - /// The sub-rectangle is useful when you don't want to display + /// The texture rect is useful when you don't want to display /// the whole texture, but rather a part of it. - /// By default, the sub-rectangle covers the entire texture. + /// By default, the texture rect covers the entire texture. /// /// \param rectangle Rectangle defining the region of the texture to display /// - /// \see GetSubRect, SetTexture + /// \see GetTextureRect, SetTexture /// //////////////////////////////////////////////////////////// - void SetSubRect(const IntRect& rectangle); + void SetTextureRect(const IntRect& rectangle); //////////////////////////////////////////////////////////// - /// \brief Change the size of the sprite + /// \brief Set the global color of the sprite /// - /// This function is just a shortcut that calls SetScale - /// with the proper values, calculated from the size of - /// the current subrect. - /// If \a width or \a height is not strictly positive, - /// this functions does nothing. + /// This color is modulated (multiplied) with the sprite's + /// texture. It can be used to colorize the sprite, or change + /// its global opacity. + /// By default, the sprite's color is opaque white. /// - /// \param width New width of the sprite - /// \param height New height of the sprite + /// \param color New color of the sprite /// - /// \see GetSize + /// \see GetColor /// //////////////////////////////////////////////////////////// - void Resize(float width, float height); - - //////////////////////////////////////////////////////////// - /// \brief Change the size of the sprite - /// - /// This function is just a shortcut that calls SetScale - /// with the proper values, calculated from the size of - /// the current subrect. - /// If \a size.x or \a size.y is not strictly positive, - /// this functions does nothing. - /// - /// \param size New size of the sprite - /// - /// \see GetSize - /// - //////////////////////////////////////////////////////////// - void Resize(const Vector2f& size); - - //////////////////////////////////////////////////////////// - /// \brief Flip the sprite horizontally - /// - /// \param flipped True to flip the sprite - /// - /// \see FlipY - /// - //////////////////////////////////////////////////////////// - void FlipX(bool flipped); - - //////////////////////////////////////////////////////////// - /// \brief Flip the sprite vertically - /// - /// \param flipped True to flip the sprite - /// - /// \see FlipX - /// - //////////////////////////////////////////////////////////// - void FlipY(bool flipped); + void SetColor(const Color& color); //////////////////////////////////////////////////////////// /// \brief Get the source texture of the sprite /// - /// If the sprite has no source texture, or if the texture - /// doesn't exist anymore, a NULL pointer is returned. + /// If the sprite has no source texture, a NULL pointer is returned. /// The returned pointer is const, which means that you can't /// modify the texture when you retrieve it with this function. /// @@ -165,48 +141,82 @@ public : const Texture* GetTexture() const; //////////////////////////////////////////////////////////// - /// \brief Get the region of the texture displayed by the sprite + /// \brief Get the sub-rectangle of the texture displayed by the sprite /// - /// \return Rectangle defining the region of the texture + /// \return Texture rectangle of the sprite /// - /// \see SetSubRect + /// \see SetTextureRect /// //////////////////////////////////////////////////////////// - const IntRect& GetSubRect() const; + const IntRect& GetTextureRect() const; //////////////////////////////////////////////////////////// - /// \brief Get the global size of the sprite + /// \brief Get the global color of the sprite /// - /// This function is a shortcut that multiplies the - /// size of the subrect by the scale factors. + /// \return Global color of the sprite /// - /// \return Size of the sprite - /// - /// \see Resize + /// \see SetColor /// //////////////////////////////////////////////////////////// - Vector2f GetSize() const; - -protected : + const Color& GetColor() const; //////////////////////////////////////////////////////////// - /// \brief Draw the object to a render target + /// \brief Get the local bounding rectangle of the entity /// - /// \param target Render target - /// \param renderer Renderer providing low-level rendering commands + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. + /// + /// \return Local bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - virtual void Render(RenderTarget& target, Renderer& renderer) const; + FloatRect GetLocalBounds() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the global bounding rectangle of the entity + /// + /// The returned rectangle is in global coordinates, which means + /// that it takes in account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// sprite in the global 2D world's coordinate system. + /// + /// \return Global bounding rectangle of the entity + /// + //////////////////////////////////////////////////////////// + FloatRect GetGlobalBounds() const; private : + //////////////////////////////////////////////////////////// + /// \brief Draw the sprite to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void Draw(RenderTarget& target, RenderStates states) const; + + //////////////////////////////////////////////////////////// + /// \brief Update the vertices' positions + /// + //////////////////////////////////////////////////////////// + void UpdatePositions(); + + //////////////////////////////////////////////////////////// + /// \brief Update the vertices' texture coordinates + /// + //////////////////////////////////////////////////////////// + void UpdateTexCoords(); + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - const Texture* myTexture; ///< Texture used to draw the sprite - IntRect mySubRect; ///< Sub-rectangle of source texture to assign to the sprite - bool myIsFlippedX; ///< Is the sprite flipped on the X axis ? - bool myIsFlippedY; ///< Is the sprite flipped on the Y axis ? + Vertex myVertices[4]; ///< Vertices defining the sprite's geometry + const Texture* myTexture; ///< Texture of the sprite + IntRect myTextureRect; ///< Rectangle defining the area of the source texture to display }; } // namespace sf @@ -222,11 +232,11 @@ private : /// sf::Sprite is a drawable class that allows to easily display /// a texture (or a part of it) on a render target. /// -/// It inherits all the functions from sf::Drawable: -/// position, rotation, scale, origin, global color and blend -/// mode. It also adds sprite-specific properties such as the -/// texture to use, the part of it to display, and some convenience -/// functions to flip or resize the sprite. +/// It inherits all the functions from sf::Transformable: +/// position, rotation, scale, origin. It also adds sprite-specific +/// properties such as the texture to use, the part of it to display, +/// and some convenience functions to change the overall color of the +/// sprite, or to get its bounding rectangle. /// /// sf::Sprite works in combination with the sf::Texture class, which /// loads and provides the pixel data of a given texture. @@ -236,11 +246,11 @@ private : /// and any operation on it is slow (often too slow for real-time /// applications). On the other side, a sf::Sprite is a lightweight /// object which can use the pixel data of a sf::Texture and draw -/// it with its own transformation / color / blending attributes. +/// it with its own transformation/color/blending attributes. /// /// It is important to note that the sf::Sprite instance doesn't /// copy the texture that it uses, it only keeps a reference to it. -/// Thus, a sf::Texture must not be destructed while it is +/// Thus, a sf::Texture must not be destroyed while it is /// used by a sf::Sprite (i.e. never write a function that /// uses a local sf::Texture instance for creating a sprite). /// @@ -253,13 +263,14 @@ private : /// // Create a sprite /// sf::Sprite sprite; /// sprite.SetTexture(texture); -/// sprite.SetSubRect(sf::IntRect(10, 10, 50, 30)); -/// sprite.Resize(100, 60); +/// sprite.SetTextureRect(sf::IntRect(10, 10, 50, 30)); +/// sprite.SetColor(sf::Color(255, 255, 255, 200)); +/// sprite.SetPosition(100, 25); /// -/// // Display it -/// window.Draw(sprite); // window is a sf::RenderWindow +/// // Draw it +/// window.Draw(sprite); /// \endcode /// -/// \see sf::Texture +/// \see sf::Texture, sf::Transformable /// //////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Text.hpp b/include/SFML/Graphics/Text.hpp index 84eccb23..5f92b8d1 100644 --- a/include/SFML/Graphics/Text.hpp +++ b/include/SFML/Graphics/Text.hpp @@ -30,9 +30,12 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include +#include #include +#include namespace sf @@ -41,7 +44,7 @@ namespace sf /// \brief Graphical text that can be drawn to a render target /// //////////////////////////////////////////////////////////// -class SFML_API Text : public Drawable +class SFML_API Text : public Drawable, public Transformable { public : @@ -99,6 +102,12 @@ public : //////////////////////////////////////////////////////////// /// \brief Set the text's font /// + /// The \a font argument refers to a texture that must + /// exist as long as the text uses it. Indeed, the text + /// doesn't store its own copy of the font, but rather keeps + /// a pointer to the one that you passed to this function. + /// If the font is destroyed and the text tries to + /// use it, the behaviour is undefined. /// Texts have a valid font by default, which the built-in /// Font::GetDefaultFont(). /// @@ -135,6 +144,18 @@ public : //////////////////////////////////////////////////////////// void SetStyle(Uint32 style); + //////////////////////////////////////////////////////////// + /// \brief Set the global color of the text + /// + /// By default, the text's color is opaque white. + /// + /// \param color New color of the text + /// + /// \see GetColor + /// + //////////////////////////////////////////////////////////// + void SetColor(const Color& color); + //////////////////////////////////////////////////////////// /// \brief Get the text's string /// @@ -187,14 +208,23 @@ public : //////////////////////////////////////////////////////////// Uint32 GetStyle() const; + //////////////////////////////////////////////////////////// + /// \brief Get the global color of the text + /// + /// \return Global color of the text + /// + /// \see SetColor + /// + //////////////////////////////////////////////////////////// + const Color& GetColor() const; + //////////////////////////////////////////////////////////// /// \brief Return the position of the \a index-th character /// /// This function computes the visual position of a character /// from its index in the string. The returned position is - /// in local coordinates (translation, rotation, scale and - /// origin are not applied). You can easily get the corresponding - /// global position with the TransformToGlobal function. + /// in global coordinates (translation, rotation, scale and + /// origin are applied). /// If \a index is out of range, the position of the end of /// the string is returned. /// @@ -203,46 +233,63 @@ public : /// \return Position of the character /// //////////////////////////////////////////////////////////// - Vector2f GetCharacterPos(std::size_t index) const; + Vector2f FindCharacterPos(std::size_t index) const; //////////////////////////////////////////////////////////// - /// \brief Get the bounding rectangle of the text + /// \brief Get the local bounding rectangle of the entity /// - /// The returned rectangle is in global coordinates. + /// The returned rectangle is in local coordinates, which means + /// that it ignores the transformations (translation, rotation, + /// scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// entity in the entity's coordinate system. /// - /// \return Bounding rectangle of the text + /// \return Local bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - FloatRect GetRect() const; - -protected : + FloatRect GetLocalBounds() const; //////////////////////////////////////////////////////////// - /// \brief Draw the object to a render target + /// \brief Get the global bounding rectangle of the entity /// - /// \param target Render target - /// \param renderer Renderer providing low-level rendering commands + /// The returned rectangle is in global coordinates, which means + /// that it takes in account the transformations (translation, + /// rotation, scale, ...) that are applied to the entity. + /// In other words, this function returns the bounds of the + /// sprite in the global 2D world's coordinate system. + /// + /// \return Global bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - virtual void Render(RenderTarget& target, Renderer& renderer) const; + FloatRect GetGlobalBounds() const; private : //////////////////////////////////////////////////////////// - /// \brief Recompute the bounding rectangle + /// \brief Draw the text to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states /// //////////////////////////////////////////////////////////// - void UpdateRect() const; + virtual void Draw(RenderTarget& target, RenderStates states) const; + + //////////////////////////////////////////////////////////// + /// \brief Update the text's geometry + /// + //////////////////////////////////////////////////////////// + void UpdateGeometry(); //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - String myString; ///< String to display - const Font* myFont; ///< Font used to display the string - unsigned int myCharacterSize; ///< Base size of characters, in pixels - Uint32 myStyle; ///< Text style (see Style enum) - mutable FloatRect myBaseRect; ///< Bounding rectangle of the text in object coordinates - mutable bool myRectUpdated; ///< Is the bounding rectangle up-to-date ? + String myString; ///< String to display + const Font* myFont; ///< Font used to display the string + unsigned int myCharacterSize; ///< Base size of characters, in pixels + Uint32 myStyle; ///< Text style (see Style enum) + Color myColor; ///< Text color + VertexArray myVertices; ///< Vertex array containing the text's geometry + FloatRect myBounds; ///< Bounding rectangle of the text (in local coordinates) }; } // namespace sf @@ -258,13 +305,13 @@ private : /// sf::Text is a drawable class that allows to easily display /// some text with custom style and color on a render target. /// -/// It inherits all the functions from sf::Drawable: -/// position, rotation, scale, origin, global color and blend -/// mode. It also adds text-specific properties such as the -/// font to use, the character size, the font style (bold, -/// italic, underlined), and the text to display of course. +/// It inherits all the functions from sf::Transformable: +/// position, rotation, scale, origin. It also adds text-specific +/// properties such as the font to use, the character size, +/// the font style (bold, italic, underlined), the global color +/// and the text to display of course. /// It also provides convenience functions to calculate the -/// graphical size of the text, or to get the visual position +/// graphical size of the text, or to get the global position /// of a given character. /// /// sf::Text works in combination with the sf::Font class, which @@ -293,12 +340,17 @@ private : /// sf::Text text("hello"); /// text.SetFont(font); /// text.SetCharacterSize(30); -/// text.SetStyle(sf::Text::Regular); +/// text.SetStyle(sf::Text::Bold); +/// text.SetColor(sf::Color::Red); /// -/// // Display it -/// window.Draw(text); // window is a sf::RenderWindow +/// // Draw it +/// window.Draw(text); /// \endcode /// -/// \see sf::Font +/// Note that you don't need to load a font to draw text, +/// SFML comes with a built-in font that is implicitely used +/// by default. +/// +/// \see sf::Font, sf::Transformable /// //////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Texture.hpp b/include/SFML/Graphics/Texture.hpp index 6f4d20a1..7a2ee5e4 100644 --- a/include/SFML/Graphics/Texture.hpp +++ b/include/SFML/Graphics/Texture.hpp @@ -35,7 +35,7 @@ namespace sf { class Window; -class Renderer; +class RenderTarget; class RenderTexture; class InputStream; @@ -45,6 +45,18 @@ class InputStream; //////////////////////////////////////////////////////////// class SFML_API Texture : GlResource { +public : + + //////////////////////////////////////////////////////////// + /// \brief Types of texture coordinates that can be used for rendering + /// + //////////////////////////////////////////////////////////// + enum CoordinateType + { + Normalized, ///< Texture coordinates in range [0 .. 1] + Pixels ///< Texture coordinates in range [0 .. size] + }; + public : //////////////////////////////////////////////////////////// @@ -353,12 +365,23 @@ public : /// \brief Activate the texture for rendering /// /// This function is mainly used internally by the SFML - /// render system. However it can be useful when + /// rendering system. However it can be useful when /// using sf::Texture together with OpenGL code (this function /// is equivalent to glBindTexture). /// + /// The \a coordinateType argument controls how texture + /// coordinates will be interpreted. If Normalized (the default), they + /// must be in range [0 .. 1], which is the default way of handling + /// texture coordinates with OpenGL. If Pixels, they must be given + /// in pixels (range [0 .. size]). This mode is used internally by + /// the graphics classes of SFML, it makes the definition of texture + /// coordinates more intuitive for the high-level API, users don't need + /// to compute normalized values. + /// + /// \param coordinateType Type of texture coordinates to use + /// //////////////////////////////////////////////////////////// - void Bind() const; + void Bind(CoordinateType coordinateType = Normalized) const; //////////////////////////////////////////////////////////// /// \brief Enable or disable the smooth filter @@ -387,18 +410,38 @@ public : bool IsSmooth() const; //////////////////////////////////////////////////////////// - /// \brief Convert a rectangle of pixels into texture coordinates + /// \brief Enable or disable repeating /// - /// This function is used by code that needs to map the texture - /// to some OpenGL geometry. It converts the source rectangle, - /// expressed in pixels, to float coordinates in the range [0, 1]. + /// Repeating is involved when using texture coordinates + /// outside the texture rectangle [0, 0, width, height]. + /// In this case, if repeat mode is enabled, the whole texture + /// will be repeated as many times as needed to reach the + /// coordinate (for example, if the X texture coordinate is + /// 3 * width, the texture will be repeated 3 times). + /// If repeat mode is disabled, the "extra space" will instead + /// be filled with border pixels. + /// Warning: on very old graphics cards, white pixels may appear + /// when the texture is repeated. With such cards, repeat mode + /// can be used reliably only if the texture has power-of-two + /// dimensions (such as 256x128). + /// Repeating is disabled by default. /// - /// \param rectangle Rectangle to convert + /// \param repeated True to repeat the texture, false to disable repeating /// - /// \return Texture coordinates corresponding to \a rectangle + /// \see IsRepeated /// //////////////////////////////////////////////////////////// - FloatRect GetTexCoords(const IntRect& rectangle) const; + void SetRepeated(bool repeated); + + //////////////////////////////////////////////////////////// + /// \brief Tell whether the texture is repeated or not + /// + /// \return True if repeat mode is enabled, false if it is disabled + /// + /// \see SetRepeated + /// + //////////////////////////////////////////////////////////// + bool IsRepeated() const; //////////////////////////////////////////////////////////// /// \brief Overload of assignment operator @@ -424,8 +467,8 @@ public : private : - friend class Renderer; friend class RenderTexture; + friend class RenderTarget; //////////////////////////////////////////////////////////// /// \brief Get a valid image size according to hardware support @@ -451,7 +494,9 @@ private : unsigned int myTextureHeight; ///< Actual texture height (can be greater than image height because of padding) unsigned int myTexture; ///< Internal texture identifier bool myIsSmooth; ///< Status of the smooth filter + bool myIsRepeated; ///< Is the texture in repeat mode? mutable bool myPixelsFlipped; ///< To work around the inconsistency in Y orientation + Uint64 myCacheId; ///< Unique number that identifies the texture to the render target's cache }; } // namespace sf @@ -514,7 +559,7 @@ private : /// sprite.SetTexture(texture); /// /// // Draw the textured sprite -/// window.Draw(sprite); // window is a sf::RenderWindow +/// window.Draw(sprite); /// \endcode /// /// \code diff --git a/include/SFML/Graphics/Transform.hpp b/include/SFML/Graphics/Transform.hpp new file mode 100644 index 00000000..026fe43e --- /dev/null +++ b/include/SFML/Graphics/Transform.hpp @@ -0,0 +1,450 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TRANSFORM_HPP +#define SFML_TRANSFORM_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a 3x3 transform matrix +/// +//////////////////////////////////////////////////////////// +class SFML_API Transform +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an identity transform (a transform that does nothing). + /// + //////////////////////////////////////////////////////////// + Transform(); + + //////////////////////////////////////////////////////////// + /// \brief Construct a transform from a 3x3 matrix + /// + /// \param a00 Element (0, 0) of the matrix + /// \param a01 Element (0, 1) of the matrix + /// \param a02 Element (0, 2) of the matrix + /// \param a10 Element (1, 0) of the matrix + /// \param a11 Element (1, 1) of the matrix + /// \param a12 Element (1, 2) of the matrix + /// \param a20 Element (2, 0) of the matrix + /// \param a21 Element (2, 1) of the matrix + /// \param a22 Element (2, 2) of the matrix + /// + //////////////////////////////////////////////////////////// + Transform(float a00, float a01, float a02, + float a10, float a11, float a12, + float a20, float a21, float a22); + + //////////////////////////////////////////////////////////// + /// \brief Return the transform as a 4x4 matrix + /// + /// This function returns a pointer to an array of 16 floats + /// containing the transform elements as a 4x4 matrix, which + /// is directly compatible with OpenGL functions. + /// + /// \code + /// sf::Transform transform = ...; + /// glLoadMatrixf(transform.GetMatrix()); + /// \endcode + /// + /// \return Pointer to a 4x4 matrix + /// + //////////////////////////////////////////////////////////// + const float* GetMatrix() const; + + //////////////////////////////////////////////////////////// + /// \brief Return the inverse of the transform + /// + /// If the inverse cannot be computed, an identity transform + /// is returned. + /// + /// \return A new transform which is the inverse of self + /// + //////////////////////////////////////////////////////////// + Transform GetInverse() const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a 2D point + /// + /// \param x X coordinate of the point to transform + /// \param y Y coordinate of the point to transform + /// + /// \return Transformed point + /// + //////////////////////////////////////////////////////////// + Vector2f TransformPoint(float x, float y) const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a 2D point + /// + /// \param point Point to transform + /// + /// \return Transformed point + /// + //////////////////////////////////////////////////////////// + Vector2f TransformPoint(const Vector2f& point) const; + + //////////////////////////////////////////////////////////// + /// \brief Transform a rectangle + /// + /// Since SFML doesn't provide support for oriented rectangles, + /// the result of this function is always an axis-aligned + /// rectangle. Which means that if the transform contains a + /// rotation, the bounding rectangle of the transformed rectangle + /// is returned. + /// + /// \param rectangle Rectangle to transform + /// + /// \return Transformed rectangle + /// + //////////////////////////////////////////////////////////// + FloatRect TransformRect(const FloatRect& rectangle) const; + + //////////////////////////////////////////////////////////// + /// \brief Combine two transforms + /// + /// The result is a transform that is equivalent to applying + /// *this followed by \a transform. Mathematically, it is + /// equivalent to a matrix multiplication. + /// + /// \param transform Transform to combine to this transform + /// + /// \return New combined transform + /// + //////////////////////////////////////////////////////////// + Transform Combine(const Transform& transform) const; + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a translation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Translate(100, 200).Rotate(45); + /// \endcode + /// + /// \param x Offset to apply on X axis + /// \param y Offset to apply on Y axis + /// + /// \return Reference to *this + /// + /// \see Rotate, Scale + /// + //////////////////////////////////////////////////////////// + Transform& Translate(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a translation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Translate(sf::Vector2f(100, 200)).Rotate(45); + /// \endcode + /// + /// \param offset Translation offset to apply + /// + /// \return Reference to *this + /// + /// \see Rotate, Scale + /// + //////////////////////////////////////////////////////////// + Transform& Translate(const Vector2f& offset); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Rotate(90).Translate(50, 20); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// + /// \return Reference to *this + /// + /// \see Translate, Scale + /// + //////////////////////////////////////////////////////////// + Transform& Rotate(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// The center of rotation is provided for convenience as a second + /// argument, so that you can build rotations around arbitrary points + /// more easily (and efficiently) than the usual + /// Translate(-center).Rotate(angle).Translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Rotate(90, 8, 3).Translate(50, 20); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// \param centerX X coordinate of the center of rotation + /// \param centerY Y coordinate of the center of rotation + /// + /// \return Reference to *this + /// + /// \see Translate, Scale + /// + //////////////////////////////////////////////////////////// + Transform& Rotate(float angle, float centerX, float centerY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a rotation + /// + /// The center of rotation is provided for convenience as a second + /// argument, so that you can build rotations around arbitrary points + /// more easily (and efficiently) than the usual + /// Translate(-center).Rotate(angle).Translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Rotate(90, sf::Vector2f(8, 3)).Translate(sf::Vector2f(50, 20)); + /// \endcode + /// + /// \param angle Rotation angle, in degrees + /// \param center Center of rotation + /// + /// \return Reference to *this + /// + /// \see Translate, Scale + /// + //////////////////////////////////////////////////////////// + Transform& Rotate(float angle, const Vector2f& center); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Scale(2, 1).Rotate(45); + /// \endcode + /// + /// \param scaleX Scaling factor on the X axis + /// \param scaleY Scaling factor on the Y axis + /// + /// \return Reference to *this + /// + /// \see Translate, Rotate + /// + //////////////////////////////////////////////////////////// + Transform& Scale(float scaleX, float scaleY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// The center of scaling is provided for convenience as a second + /// argument, so that you can build scaling around arbitrary points + /// more easily (and efficiently) than the usual + /// Translate(-center).Scale(factors).Translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Scale(2, 1, 8, 3).Rotate(45); + /// \endcode + /// + /// \param scaleX Scaling factor on X axis + /// \param scaleY Scaling factor on Y axis + /// \param centerX X coordinate of the center of scaling + /// \param centerY Y coordinate of the center of scaling + /// + /// \return Reference to *this + /// + /// \see Translate, Rotate + /// + //////////////////////////////////////////////////////////// + Transform& Scale(float scaleX, float scaleY, float centerX, float centerY); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Scale(sf::Vector2f(2, 1)).Rotate(45); + /// \endcode + /// + /// \param factors Scaling factors + /// + /// \return Reference to *this + /// + /// \see Translate, Rotate + /// + //////////////////////////////////////////////////////////// + Transform& Scale(const Vector2f& factors); + + //////////////////////////////////////////////////////////// + /// \brief Combine the current transform with a scaling + /// + /// The center of scaling is provided for convenience as a second + /// argument, so that you can build scaling around arbitrary points + /// more easily (and efficiently) than the usual + /// Translate(-center).Scale(factors).Translate(center). + /// + /// This function returns a reference to *this, so that calls + /// can be chained. + /// \code + /// sf::Transform transform; + /// transform.Scale(sf::Vector2f(2, 1), sf::Vector2f(8, 3)).Rotate(45); + /// \endcode + /// + /// \param factors Scaling factors + /// \param center Center of scaling + /// + /// \return Reference to *this + /// + /// \see Translate, Rotate + /// + //////////////////////////////////////////////////////////// + Transform& Scale(const Vector2f& factors, const Vector2f& center); + + //////////////////////////////////////////////////////////// + // Static member data + //////////////////////////////////////////////////////////// + static const Transform Identity; ///< The identity transform (does nothing) + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float myMatrix[16]; ///< 4x4 matrix defining the transformation +}; + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator * to combine two transforms +/// +/// This call is equivalent to calling left.Combine(right). +/// +/// \param left Left operand (the first transform) +/// \param right Right operand (the second transform) +/// +/// \return New combined transform +/// +//////////////////////////////////////////////////////////// +SFML_API Transform operator *(const Transform& left, const Transform& right); + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator *= to combine two transforms +/// +/// This call is equivalent to calling left = left.Combine(right). +/// +/// \param left Left operand (the first transform) +/// \param right Right operand (the second transform) +/// +/// \return The combined transform +/// +//////////////////////////////////////////////////////////// +SFML_API Transform& operator *=(Transform& left, const Transform& right); + +//////////////////////////////////////////////////////////// +/// \relates sf::Transform +/// \brief Overload of binary operator * to transform a point +/// +/// This call is equivalent to calling left.TransformPoint(right). +/// +/// \param left Left operand (the transform) +/// \param right Right operand (the point to transform) +/// +/// \return New transformed point +/// +//////////////////////////////////////////////////////////// +SFML_API Vector2f operator *(const Transform& left, const Vector2f& right); + +} // namespace sf + + +#endif // SFML_TRANSFORM_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Transform +/// \ingroup graphics +/// +/// A sf::Transform specifies how to translate, rotate, scale, +/// shear, project, whatever things. In mathematical terms, it defines +/// how to transform a coordinate system into another. +/// +/// For example, if you apply a rotation transform to a sprite, the +/// result will be a rotated sprite. And anything that is transformed +/// by this rotation transform will be rotated the same way, according +/// to its initial position. +/// +/// Transforms are typically used for drawing. But they can also be +/// used for any computation that requires to transform points between +/// the local and global coordinate systems of an entity (like collision +/// detection). +/// +/// Example: +/// \code +/// // define a translation transform +/// sf::Transform translation; +/// translation.Translate(20, 50); +/// +/// // define a rotation transform +/// sf::Transform rotation; +/// rotation.Rotate(45); +/// +/// // combine them +/// sf::Transform transform = translation * rotation; +/// +/// // use the result to transform stuff... +/// sf::Vector2f point = transform.TransformPoint(10, 20); +/// sf::FloatRect rect = transform.TransformRect(sf::FloatRect(0, 0, 10, 100)); +/// \endcode +/// +/// \see sf::Transformable, sf::RenderStates +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Transformable.hpp b/include/SFML/Graphics/Transformable.hpp new file mode 100644 index 00000000..e42af36c --- /dev/null +++ b/include/SFML/Graphics/Transformable.hpp @@ -0,0 +1,416 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TRANSFORMABLE_HPP +#define SFML_TRANSFORMABLE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Decomposed transform defined by a position, a rotation and a scale +/// +//////////////////////////////////////////////////////////// +class SFML_API Transformable +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Transformable(); + + //////////////////////////////////////////////////////////// + /// \brief Virtual destructor + /// + //////////////////////////////////////////////////////////// + virtual ~Transformable(); + + //////////////////////////////////////////////////////////// + /// \brief Set the position of the object + /// + /// This function completely overwrites the previous position. + /// See Move to apply an offset based on the previous position instead. + /// The default position of a transformable object is (0, 0). + /// + /// \param x X coordinate of the new position + /// \param y Y coordinate of the new position + /// + /// \see Move, GetPosition + /// + //////////////////////////////////////////////////////////// + void SetPosition(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Set the position of the object + /// + /// This function completely overwrites the previous position. + /// See Move to apply an offset based on the previous position instead. + /// The default position of a transformable object is (0, 0). + /// + /// \param position New position + /// + /// \see Move, GetPosition + /// + //////////////////////////////////////////////////////////// + void SetPosition(const Vector2f& position); + + //////////////////////////////////////////////////////////// + /// \brief Set the orientation of the object + /// + /// This function completely overwrites the previous rotation. + /// See Rotate to add an angle based on the previous rotation instead. + /// The default rotation of a transformable object is 0. + /// + /// \param angle New rotation, in degrees + /// + /// \see Rotate, GetRotation + /// + //////////////////////////////////////////////////////////// + void SetRotation(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Set the scale factors of the object + /// + /// This function completely overwrites the previous scale. + /// See Scale to add a factor based on the previous scale instead. + /// The default scale of a transformable object is (1, 1). + /// + /// \param factorX New horizontal scale factor + /// \param factorY New vertical scale factor + /// + /// \see Scale, GetScale + /// + //////////////////////////////////////////////////////////// + void SetScale(float factorX, float factorY); + + //////////////////////////////////////////////////////////// + /// \brief Set the scale factors of the object + /// + /// This function completely overwrites the previous scale. + /// See Scale to add a factor based on the previous scale instead. + /// The default scale of a transformable object is (1, 1). + /// + /// \param factors New scale factors + /// + /// \see Scale, GetScale + /// + //////////////////////////////////////////////////////////// + void SetScale(const Vector2f& factors); + + //////////////////////////////////////////////////////////// + /// \brief Set the local origin of the object + /// + /// The origin of an object defines the center point for + /// all transformations (position, scale, rotation). + /// The coordinates of this point must be relative to the + /// top-left corner of the object, and ignore all + /// transformations (position, scale, rotation). + /// The default origin of a transformable object is (0, 0). + /// + /// \param x X coordinate of the new origin + /// \param y Y coordinate of the new origin + /// + /// \see GetOrigin + /// + //////////////////////////////////////////////////////////// + void SetOrigin(float x, float y); + + //////////////////////////////////////////////////////////// + /// \brief Set the local origin of the object + /// + /// The origin of an object defines the center point for + /// all transformations (position, scale, rotation). + /// The coordinates of this point must be relative to the + /// top-left corner of the object, and ignore all + /// transformations (position, scale, rotation). + /// The default origin of a transformable object is (0, 0). + /// + /// \param origin New origin + /// + /// \see GetOrigin + /// + //////////////////////////////////////////////////////////// + void SetOrigin(const Vector2f& origin); + + //////////////////////////////////////////////////////////// + /// \brief Get the position of the object + /// + /// \return Current position + /// + /// \see SetPosition + /// + //////////////////////////////////////////////////////////// + const Vector2f& GetPosition() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the orientation of the object + /// + /// The rotation is always in the range [0, 360]. + /// + /// \return Current rotation, in degrees + /// + /// \see SetRotation + /// + //////////////////////////////////////////////////////////// + float GetRotation() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the current scale of the object + /// + /// \return Current scale factors + /// + /// \see SetScale + /// + //////////////////////////////////////////////////////////// + const Vector2f& GetScale() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the local origin of the object + /// + /// \return Current origin + /// + /// \see SetOrigin + /// + //////////////////////////////////////////////////////////// + const Vector2f& GetOrigin() const; + + //////////////////////////////////////////////////////////// + /// \brief Move the object by a given offset + /// + /// This function adds to the current position of the object, + /// unlike SetPosition which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f pos = object.GetPosition(); + /// object.SetPosition(pos.x + offsetX, pos.y + offsetY); + /// \endcode + /// + /// \param offsetX X offset + /// \param offsetY Y offset + /// + /// \see SetPosition + /// + //////////////////////////////////////////////////////////// + void Move(float offsetX, float offsetY); + + //////////////////////////////////////////////////////////// + /// \brief Move the object by a given offset + /// + /// This function adds to the current position of the object, + /// unlike SetPosition which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// object.SetPosition(object.GetPosition() + offset); + /// \endcode + /// + /// \param offset Offset + /// + /// \see SetPosition + /// + //////////////////////////////////////////////////////////// + void Move(const Vector2f& offset); + + //////////////////////////////////////////////////////////// + /// \brief Rotate the object + /// + /// This function adds to the current rotation of the object, + /// unlike SetRotation which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// object.SetRotation(object.GetRotation() + angle); + /// \endcode + /// + /// \param angle Angle of rotation, in degrees + /// + //////////////////////////////////////////////////////////// + void Rotate(float angle); + + //////////////////////////////////////////////////////////// + /// \brief Scale the object + /// + /// This function multiplies the current scale of the object, + /// unlike SetScale which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f scale = object.GetScale(); + /// object.SetScale(scale.x * factorX, scale.y * factorY); + /// \endcode + /// + /// \param factorX Horizontal scale factor + /// \param factorY Vertical scale factor + /// + /// \see SetScale + /// + //////////////////////////////////////////////////////////// + void Scale(float factorX, float factorY); + + //////////////////////////////////////////////////////////// + /// \brief Scale the object + /// + /// This function multiplies the current scale of the object, + /// unlike SetScale which overwrites it. + /// Thus, it is equivalent to the following code: + /// \code + /// sf::Vector2f scale = object.GetScale(); + /// object.SetScale(scale.x * factor.x, scale.y * factor.y); + /// \endcode + /// + /// \param factor Scale factors + /// + /// \see SetScale + /// + //////////////////////////////////////////////////////////// + void Scale(const Vector2f& factor); + + //////////////////////////////////////////////////////////// + /// \brief Get the combined transform of the object + /// + /// \return Transform combining the position/rotation/scale/origin of the object + /// + /// \see GetInverseTransform + /// + //////////////////////////////////////////////////////////// + const Transform& GetTransform() const; + + //////////////////////////////////////////////////////////// + /// \brief Get the inverse of the combined transform of the object + /// + /// \return Inversed of the combined transformations applied to the object + /// + /// \see GetTransform + /// + //////////////////////////////////////////////////////////// + const Transform& GetInverseTransform() const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f myOrigin; ///< Origin of translation/rotation/scaling of the object + Vector2f myPosition; ///< Position of the object in the 2D world + float myRotation; ///< Orientation of the object, in degrees + Vector2f myScale; ///< Scale of the object + mutable Transform myTransform; ///< Combined transformation of the object + mutable bool myTransformNeedUpdate; ///< Does the transform need to be recomputed? + mutable Transform myInverseTransform; ///< Combined transformation of the object + mutable bool myInverseTransformNeedUpdate; ///< Does the transform need to be recomputed? +}; + +} // namespace sf + + +#endif // SFML_TRANSFORMABLE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Transformable +/// \ingroup graphics +/// +/// This class is provided for convenience, on top of sf::Transform. +/// +/// sf::Transform, as a low-level class, offers a great level of +/// flexibility but it is not always convenient to manage. Indeed, +/// one can easily combine any kind of operation, such as a translation +/// followed by a rotation followed by a scaling, but once the result +/// transform is built, there's no way to go backward and, let's say, +/// change only the rotation without modifying the translation and scaling. +/// The entire transform must be recomputed, which means that you +/// need to retrieve the initial translation and scale factors as +/// well, and combine them the same way you did before updating the +/// rotation. This is a tedious operation, and it requires to store +/// all the individual components of the final transform. +/// +/// That's exactly what sf::Transformable was written for: it hides +/// these variables and the composed transform behind an easy to use +/// interface. You can set or get any of the individual components +/// without worrying about the others. It also provides the composed +/// transform (as a sf::Transform), and keeps it up-to-date. +/// +/// In addition to the position, rotation and scale, sf::Transformable +/// provides an "origin" component, which represents the local origin +/// of the three other components. Let's take an example with a 10x10 +/// pixels sprite. By default, the sprite is positionned/rotated/scaled +/// relatively to its top-left corner, because it is the local point +/// (0, 0). But if we change the origin to be (5, 5), the sprite will +/// be positionned/rotated/scaled around its center instead. And if +/// we set the origin to (10, 10), it will be transformed around its +/// bottom-right corner. +/// +/// To keep the sf::Transformable class simple, there's only one +/// origin for all the components. You cannot position the sprite +/// relatively to its top-left corner while rotating it around its +/// center, for example. To do such things, use sf::Transform directly. +/// +/// sf::Transformable can be used as a base class. It is often +/// combined with sf::Drawable -- that's what SFML's sprites, +/// texts and shapes do. +/// \code +/// class MyEntity : public sf::Transformable, public sf::Drawable +/// { +/// virtual void Draw(sf::RenderTarget& target, sf::RenderStates states) const +/// { +/// states.Transform *= GetTransform(); +/// target.Draw(..., states); +/// } +/// }; +/// +/// MyEntity entity; +/// entity.SetPosition(10, 20); +/// entity.SetRotation(45); +/// window.Draw(entity); +/// \endcode +/// +/// It can also be used as a member, if you don't want to use +/// its API directly (because you don't need all its functions, +/// or you have different naming conventions for example). +/// \code +/// class MyEntity +/// { +/// public : +/// void setPosition(const MyVector& v) +/// { +/// m_transform.SetPosition(v.x(), v.y()); +/// } +/// +/// void draw(sf::RenderTarget& target) const +/// { +/// target.Draw(..., m_transform.GetTransform()); +/// } +/// +/// private : +/// sf::Transformable m_transform; +/// }; +/// \endcode +/// +/// \see sf::Transform +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Vertex.hpp b/include/SFML/Graphics/Vertex.hpp new file mode 100644 index 00000000..f7e9ae60 --- /dev/null +++ b/include/SFML/Graphics/Vertex.hpp @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VERTEX_HPP +#define SFML_VERTEX_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a point with color and texture coordinates +/// +//////////////////////////////////////////////////////////// +class SFML_API Vertex +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + Vertex(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position + /// + /// The vertex color is white and texture coordinates are (0, 0). + /// + /// \param position Vertex position + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& position); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position and color + /// + /// The texture coordinates are (0, 0). + /// + /// \param position Vertex position + /// \param color Vertex color + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& position, const sf::Color& color); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position and texture coordinates + /// + /// The vertex color is white. + /// + /// \param position Vertex position + /// \param texCoords Vertex texture coordinates + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& position, const Vector2f& texCoords); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex from its position, color and texture coordinates + /// + /// \param position Vertex position + /// \param color Vertex color + /// \param texCoords Vertex texture coordinates + /// + //////////////////////////////////////////////////////////// + Vertex(const Vector2f& position, const sf::Color& color, const Vector2f& texCoords); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f Position; ///< 2D position of the vertex + sf::Color Color; ///< Color of the vertex + Vector2f TexCoords; ///< Coordinates of the texture's pixel to map to the vertex +}; + +} // namespace sf + + +#endif // SFML_VERTEX_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Vertex +/// \ingroup graphics +/// +/// A vertex is an improved point. It has a position and other +/// extra attributes that will be used for drawing: in SFML, +/// vertices also have a color and a pair of texture coordinates. +/// +/// The vertex is the building block of drawing. Everything which +/// is visible on screen is made of vertices. They are grouped +/// as 2D primitives (triangles, quads, ...), and these primitives +/// are grouped to create even more complex 2D entities such as +/// sprites, texts, etc. +/// +/// If you use the graphical entities of SFML (sprite, text, shape) +/// you won't have to deal with vertices directly. But if you want +/// to define your own 2D entities, such as tiled maps or particle +/// systems, using vertices will allow you to get maximum performances. +/// +/// Example: +/// \code +/// // define a 100x100 square, red, with a 10x10 texture mapped on it +/// sf::Vertex vertices[] = +/// { +/// sf::Vertex(sf::Vector2f( 0, 0), sf::Color::Red, sf::Vector2f( 0, 0)), +/// sf::Vertex(sf::Vector2f( 0, 100), sf::Color::Red, sf::Vector2f( 0, 10)), +/// sf::Vertex(sf::Vector2f(100, 100), sf::Color::Red, sf::Vector2f(10, 10)), +/// sf::Vertex(sf::Vector2f(100, 0), sf::Color::Red, sf::Vector2f(10, 0)) +/// }; +/// +/// // draw it +/// window.Draw(vertices, 4, sf::Quads); +/// \endcode +/// +/// Note: although texture coordinates are supposed to be an integer +/// amount of pixels, their type is float because of some buggy graphics +/// drivers that are not able to process integer coordinates correctly. +/// +/// \see sf::VertexArray +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/VertexArray.hpp b/include/SFML/Graphics/VertexArray.hpp new file mode 100644 index 00000000..5c847054 --- /dev/null +++ b/include/SFML/Graphics/VertexArray.hpp @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_VERTEXARRAY_HPP +#define SFML_VERTEXARRAY_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Define a set of one or more 2D primitives +/// +//////////////////////////////////////////////////////////// +class SFML_API VertexArray : public Drawable +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates an empty vertex array. + /// + //////////////////////////////////////////////////////////// + VertexArray(); + + //////////////////////////////////////////////////////////// + /// \brief Construct the vertex array with a type and an initial number of vertices + /// + /// \param type Type of primitives + /// \param verticesCount Initial number of vertices in the array + /// + //////////////////////////////////////////////////////////// + VertexArray(PrimitiveType type, unsigned int verticesCount = 0); + + //////////////////////////////////////////////////////////// + /// \brief Return the vertices count + /// + /// \return Number of vertices in the array + /// + //////////////////////////////////////////////////////////// + unsigned int GetVerticesCount() const; + + //////////////////////////////////////////////////////////// + /// \brief Get a read-write access to a vertex by its index + /// + /// This function doesn't check \a index, it must be in range + /// [0, GetVerticesCount() - 1]. + /// + /// \param index Index of the vertex to get + /// + /// \return Reference to the index-th vertex + /// + /// \see GetVerticesCount + /// + //////////////////////////////////////////////////////////// + Vertex& operator [](unsigned int index); + + //////////////////////////////////////////////////////////// + /// \brief Get a read-only access to a vertex by its index + /// + /// This function doesn't check \a index, it must be in range + /// [0, GetVerticesCount() - 1]. + /// + /// \param index Index of the vertex to get + /// + /// \return Const reference to the index-th vertex + /// + /// \see GetVerticesCount + /// + //////////////////////////////////////////////////////////// + const Vertex& operator [](unsigned int index) const; + + //////////////////////////////////////////////////////////// + /// \brief Clear the vertex array + /// + /// This function removes all the vertices from the array. + /// It doesn't deallocate the corresponding memory, so that + /// adding new vertices after clearing doesn't involve + /// reallocating all the memory. + /// + //////////////////////////////////////////////////////////// + void Clear(); + + //////////////////////////////////////////////////////////// + /// \brief Resize the vertex array + /// + /// If \a count is greater than the current size, the previous + /// vertices are kept and new (default-constructed) vertices are + /// added. + /// If \a count is less than the current size, existing vertices + /// are removed from the array. + /// + /// \param verticesCount New size of the array (number of vertices) + /// + //////////////////////////////////////////////////////////// + void Resize(unsigned int verticesCount); + + //////////////////////////////////////////////////////////// + /// \brief Add a vertex to the array + /// + /// \param vertex Vertex to add + /// + //////////////////////////////////////////////////////////// + void Append(const Vertex& vertex); + + //////////////////////////////////////////////////////////// + /// \brief Set the type of primitives to draw + /// + /// This function defines how the vertices must be interpreted + /// when it's time to draw them: + /// \li As points + /// \li As lines + /// \li As triangles + /// \li As quads + /// The default primitive type is sf::Points. + /// + /// \param type Type of primitive + /// + //////////////////////////////////////////////////////////// + void SetPrimitiveType(PrimitiveType type); + + //////////////////////////////////////////////////////////// + /// \brief Get the type of primitives drawn by the vertex array + /// + /// \return Primitive type + /// + //////////////////////////////////////////////////////////// + PrimitiveType GetPrimitiveType() const; + + //////////////////////////////////////////////////////////// + /// \brief Compute the bounding rectangle of the vertex array + /// + /// This function returns the axis-aligned rectangle that + /// contains all the vertices of the array. + /// + /// \return Bounding rectangle of the vertex array + /// + //////////////////////////////////////////////////////////// + FloatRect GetBounds() const; + +private : + + //////////////////////////////////////////////////////////// + /// \brief Draw the vertex array to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states + /// + //////////////////////////////////////////////////////////// + virtual void Draw(RenderTarget& target, RenderStates states) const; + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + std::vector myVertices; ///< Vertices contained in the array + PrimitiveType myPrimitiveType; ///< Type of primitives to draw +}; + +} // namespace sf + + +#endif // SFML_VERTEXARRAY_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::VertexArray +/// \ingroup graphics +/// +/// sf::VertexArray is a very simple wrapper around a dynamic +/// array of vertices and a primitives type. +/// +/// It inherits sf::Drawable, but unlike other drawables it +/// is not transformable. +/// +/// Example: +/// \code +/// sf::VertexArray lines(sf::LinesStrip, 4); +/// lines[0].Position = sf::Vector2f(10, 0); +/// lines[1].Position = sf::Vector2f(20, 0); +/// lines[2].Position = sf::Vector2f(30, 5); +/// lines[3].Position = sf::Vector2f(40, 2); +/// +/// window.Draw(lines); +/// \endcode +/// +/// \see sf::Vertex +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/View.hpp b/include/SFML/Graphics/View.hpp index 14a0b947..dee4eb49 100644 --- a/include/SFML/Graphics/View.hpp +++ b/include/SFML/Graphics/View.hpp @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include #include @@ -241,42 +241,42 @@ public : void Zoom(float factor); //////////////////////////////////////////////////////////// - /// \brief Get the projection matrix of the view + /// \brief Get the projection transform of the view /// - /// This functions is meant for internal use only. + /// This function is meant for internal use only. /// - /// \return Projection matrix defining the view + /// \return Projection transform defining the view /// - /// \see GetInverseMatrix + /// \see GetInverseTransform /// //////////////////////////////////////////////////////////// - const Matrix3& GetMatrix() const; + const Transform& GetTransform() const; //////////////////////////////////////////////////////////// - /// \brief Get the inverse projection matrix of the view + /// \brief Get the inverse projection transform of the view /// - /// This functions is meant for internal use only. + /// This function is meant for internal use only. /// - /// \return Inverse of the projection matrix defining the view + /// \return Inverse of the projection transform defining the view /// - /// \see GetMatrix + /// \see GetTransform /// //////////////////////////////////////////////////////////// - const Matrix3& GetInverseMatrix() const; + const Transform& GetInverseTransform() const; private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - Vector2f myCenter; ///< Center of the view, in scene coordinates - Vector2f mySize; ///< Size of the view, in scene coordinates - float myRotation; ///< Angle of rotation of the view rectangle, in degrees - FloatRect myViewport; ///< Viewport rectangle, expressed as a factor of the render-target's size - mutable Matrix3 myMatrix; ///< Precomputed projection matrix corresponding to the view - mutable Matrix3 myInverseMatrix; ///< Precomputed inverse projection matrix corresponding to the view - mutable bool myMatrixUpdated; ///< Internal state telling if the matrix needs to be updated - mutable bool myInvMatrixUpdated; ///< Internal state telling if the matrix needs to be updated + Vector2f myCenter; ///< Center of the view, in scene coordinates + Vector2f mySize; ///< Size of the view, in scene coordinates + float myRotation; ///< Angle of rotation of the view rectangle, in degrees + FloatRect myViewport; ///< Viewport rectangle, expressed as a factor of the render-target's size + mutable Transform myTransform; ///< Precomputed projection transform corresponding to the view + mutable Transform myInverseTransform; ///< Precomputed inverse projection transform corresponding to the view + mutable bool myTransformUpdated; ///< Internal state telling if the transform needs to be updated + mutable bool myInvTransformUpdated; ///< Internal state telling if the inverse transform needs to be updated }; } // namespace sf diff --git a/include/SFML/System/Utf.hpp b/include/SFML/System/Utf.hpp index 5fe481b6..f322f26d 100644 --- a/include/SFML/System/Utf.hpp +++ b/include/SFML/System/Utf.hpp @@ -149,7 +149,6 @@ public : /// \param begin Iterator pointing to the beginning of the input sequence /// \param end Iterator pointing to the end of the input sequence /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion /// /// \return Iterator to the end of the output sequence which has been written /// @@ -357,7 +356,6 @@ public : /// \param begin Iterator pointing to the beginning of the input sequence /// \param end Iterator pointing to the end of the input sequence /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion /// /// \return Iterator to the end of the output sequence which has been written /// @@ -566,7 +564,6 @@ public : /// \param begin Iterator pointing to the beginning of the input sequence /// \param end Iterator pointing to the end of the input sequence /// \param output Iterator pointing to the beginning of the output sequence - /// \param locale Locale to use for conversion /// /// \return Iterator to the end of the output sequence which has been written /// diff --git a/include/SFML/System/Vector3.hpp b/include/SFML/System/Vector3.hpp index 64042890..dd438c59 100644 --- a/include/SFML/System/Vector3.hpp +++ b/include/SFML/System/Vector3.hpp @@ -82,7 +82,7 @@ public : /// \relates Vector3 /// \brief Overload of unary operator - /// -/// \param right Vector to negate +/// \param left Vector to negate /// /// \return Memberwise opposite of the vector /// diff --git a/src/SFML/Graphics/CMakeLists.txt b/src/SFML/Graphics/CMakeLists.txt index 5597ff22..8856fb12 100644 --- a/src/SFML/Graphics/CMakeLists.txt +++ b/src/SFML/Graphics/CMakeLists.txt @@ -5,9 +5,9 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Graphics) # all source files set(SRC ${SRCROOT}/Arial.hpp + ${INCROOT}/BlendMode.hpp ${SRCROOT}/Color.cpp ${INCROOT}/Color.hpp - ${SRCROOT}/Drawable.cpp ${INCROOT}/Drawable.hpp ${SRCROOT}/Font.cpp ${INCROOT}/Font.hpp @@ -18,13 +18,11 @@ set(SRC ${INCROOT}/Image.hpp ${SRCROOT}/ImageLoader.cpp ${SRCROOT}/ImageLoader.hpp - ${SRCROOT}/Matrix3.cpp - ${INCROOT}/Matrix3.hpp - ${INCROOT}/Matrix3.inl + ${INCROOT}/PrimitiveType.hpp ${INCROOT}/Rect.hpp ${INCROOT}/Rect.inl - ${SRCROOT}/Renderer.cpp - ${INCROOT}/Renderer.hpp + ${SRCROOT}/RenderStates.cpp + ${INCROOT}/RenderStates.hpp ${SRCROOT}/RenderTexture.cpp ${INCROOT}/RenderTexture.hpp ${SRCROOT}/RenderTextureImpl.cpp @@ -41,14 +39,30 @@ set(SRC ${INCROOT}/Shader.hpp ${SRCROOT}/Shape.cpp ${INCROOT}/Shape.hpp + ${SRCROOT}/CircleShape.cpp + ${INCROOT}/CircleShape.hpp + ${SRCROOT}/RectangleShape.cpp + ${INCROOT}/RectangleShape.hpp + ${SRCROOT}/ConvexShape.cpp + ${INCROOT}/ConvexShape.hpp ${SRCROOT}/Sprite.cpp ${INCROOT}/Sprite.hpp ${SRCROOT}/Text.cpp ${INCROOT}/Text.hpp ${SRCROOT}/Texture.cpp ${INCROOT}/Texture.hpp + ${SRCROOT}/TextureSaver.cpp + ${SRCROOT}/TextureSaver.hpp + ${SRCROOT}/Transform.cpp + ${INCROOT}/Transform.hpp + ${SRCROOT}/Transformable.cpp + ${INCROOT}/Transformable.hpp ${SRCROOT}/View.cpp ${INCROOT}/View.hpp + ${SRCROOT}/Vertex.cpp + ${INCROOT}/Vertex.hpp + ${SRCROOT}/VertexArray.cpp + ${INCROOT}/VertexArray.hpp ${SRCROOT}/stb_image/stb_image.h ${SRCROOT}/stb_image/stb_image_write.h ) diff --git a/src/SFML/Graphics/CircleShape.cpp b/src/SFML/Graphics/CircleShape.cpp new file mode 100644 index 00000000..4d6b0e89 --- /dev/null +++ b/src/SFML/Graphics/CircleShape.cpp @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +CircleShape::CircleShape(float radius, unsigned int pointsCount) : +myRadius (radius), +myPointsCount(pointsCount) +{ + Update(); +} + + +//////////////////////////////////////////////////////////// +void CircleShape::SetRadius(float radius) +{ + myRadius = radius; + Update(); +} + + +//////////////////////////////////////////////////////////// +float CircleShape::GetRadius() const +{ + return myRadius; +} + + +//////////////////////////////////////////////////////////// +void CircleShape::SetPointsCount(unsigned int count) +{ + myPointsCount = count; + Update(); +} + +//////////////////////////////////////////////////////////// +unsigned int CircleShape::GetPointsCount() const +{ + return myPointsCount; +} + + +//////////////////////////////////////////////////////////// +Vector2f CircleShape::GetPoint(unsigned int index) const +{ + static const float pi = 3.141592654f; + + float angle = index * 2 * pi / myPointsCount - pi / 2; + float x = std::cos(angle) * myRadius; + float y = std::sin(angle) * myRadius; + + return Vector2f(myRadius + x, myRadius + y); +} + +} // namespace sf diff --git a/src/SFML/Graphics/Color.cpp b/src/SFML/Graphics/Color.cpp index 0c6fccf0..bef16d5e 100644 --- a/src/SFML/Graphics/Color.cpp +++ b/src/SFML/Graphics/Color.cpp @@ -42,6 +42,7 @@ const Color Color::Blue(0, 0, 255); const Color Color::Yellow(255, 255, 0); const Color Color::Magenta(255, 0, 255); const Color Color::Cyan(0, 255, 255); +const Color Color::Transparent(0, 0, 0, 0); //////////////////////////////////////////////////////////// diff --git a/src/SFML/Graphics/ConvexShape.cpp b/src/SFML/Graphics/ConvexShape.cpp new file mode 100644 index 00000000..d60b583b --- /dev/null +++ b/src/SFML/Graphics/ConvexShape.cpp @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +ConvexShape::ConvexShape(unsigned int pointsCount) +{ + SetPointsCount(pointsCount); +} + + +//////////////////////////////////////////////////////////// +void ConvexShape::SetPointsCount(unsigned int count) +{ + myPoints.resize(count); + Update(); +} + + +//////////////////////////////////////////////////////////// +unsigned int ConvexShape::GetPointsCount() const +{ + return myPoints.size(); +} + + +//////////////////////////////////////////////////////////// +void ConvexShape::SetPoint(unsigned int index, const Vector2f& point) +{ + myPoints[index] = point; + Update(); +} + + +//////////////////////////////////////////////////////////// +Vector2f ConvexShape::GetPoint(unsigned int index) const +{ + return myPoints[index]; +} + +} // namespace sf diff --git a/src/SFML/Graphics/Drawable.cpp b/src/SFML/Graphics/Drawable.cpp deleted file mode 100644 index 5dd4336f..00000000 --- a/src/SFML/Graphics/Drawable.cpp +++ /dev/null @@ -1,314 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include - - -namespace sf -{ -//////////////////////////////////////////////////////////// -Drawable::~Drawable() -{ - // Nothing to do -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetPosition(float x, float y) -{ - SetX(x); - SetY(y); -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetPosition(const Vector2f& position) -{ - SetX(position.x); - SetY(position.y); -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetX(float x) -{ - myPosition.x = x; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetY(float y) -{ - myPosition.y = y; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetScale(float factorX, float factorY) -{ - SetScaleX(factorX); - SetScaleY(factorY); -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetScale(const Vector2f& factors) -{ - SetScaleX(factors.x); - SetScaleY(factors.y); -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetScaleX(float factor) -{ - if (factor > 0) - { - myScale.x = factor; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; - } -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetScaleY(float factor) -{ - if (factor > 0) - { - myScale.y = factor; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; - } -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetOrigin(float x, float y) -{ - myOrigin.x = x; - myOrigin.y = y; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetOrigin(const Vector2f& origin) -{ - SetOrigin(origin.x, origin.y); -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetRotation(float angle) -{ - myRotation = static_cast(std::fmod(angle, 360)); - if (myRotation < 0) - myRotation += 360.f; - - myMatrixUpdated = false; - myInvMatrixUpdated = false; -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetColor(const Color& color) -{ - myColor = color; -} - - -//////////////////////////////////////////////////////////// -void Drawable::SetBlendMode(Blend::Mode mode) -{ - myBlendMode = mode; -} - - -//////////////////////////////////////////////////////////// -const Vector2f& Drawable::GetPosition() const -{ - return myPosition; -} - - -//////////////////////////////////////////////////////////// -const Vector2f& Drawable::GetScale() const -{ - return myScale; -} - - -//////////////////////////////////////////////////////////// -const Vector2f& Drawable::GetOrigin() const -{ - return myOrigin; -} - - -//////////////////////////////////////////////////////////// -float Drawable::GetRotation() const -{ - return myRotation; -} - - -//////////////////////////////////////////////////////////// -const Color& Drawable::GetColor() const -{ - return myColor; -} - - -//////////////////////////////////////////////////////////// -Blend::Mode Drawable::GetBlendMode() const -{ - return myBlendMode; -} - - -//////////////////////////////////////////////////////////// -void Drawable::Move(float offsetX, float offsetY) -{ - SetPosition(myPosition.x + offsetX, myPosition.y + offsetY); -} - - -//////////////////////////////////////////////////////////// -void Drawable::Move(const Vector2f& offset) -{ - SetPosition(myPosition + offset); -} - - -//////////////////////////////////////////////////////////// -void Drawable::Scale(float factorX, float factorY) -{ - SetScale(myScale.x * factorX, myScale.y * factorY); -} - - -//////////////////////////////////////////////////////////// -void Drawable::Scale(const Vector2f& factor) -{ - SetScale(myScale.x * factor.x, myScale.y * factor.y); -} - - -//////////////////////////////////////////////////////////// -void Drawable::Rotate(float angle) -{ - SetRotation(myRotation + angle); -} - - -//////////////////////////////////////////////////////////// -Vector2f Drawable::TransformToLocal(const Vector2f& point) const -{ - return GetInverseMatrix().Transform(point); -} - - -//////////////////////////////////////////////////////////// -Vector2f Drawable::TransformToGlobal(const Vector2f& point) const -{ - return GetMatrix().Transform(point); -} - - -//////////////////////////////////////////////////////////// -Drawable::Drawable() : -myPosition (0, 0), -myScale (1, 1), -myOrigin (0, 0), -myRotation (0), -myColor (255, 255, 255, 255), -myBlendMode (Blend::Alpha), -myMatrixUpdated (false), -myInvMatrixUpdated(false) -{ -} - - -//////////////////////////////////////////////////////////// -const Matrix3& Drawable::GetMatrix() const -{ - // First recompute it if needed - if (!myMatrixUpdated) - { - myMatrix = Matrix3::Transformation(myOrigin, myPosition, myRotation, myScale); - myMatrixUpdated = true; - } - - return myMatrix; -} - - -//////////////////////////////////////////////////////////// -const Matrix3& Drawable::GetInverseMatrix() const -{ - // First recompute it if needed - if (!myInvMatrixUpdated) - { - myInvMatrix = GetMatrix().GetInverse(); - myInvMatrixUpdated = true; - } - - return myInvMatrix; -} - - -//////////////////////////////////////////////////////////// -void Drawable::Draw(RenderTarget& target, Renderer& renderer) const -{ - // Set the current model-view matrix - renderer.ApplyModelView(GetMatrix()); - - // Set the current global color - renderer.ApplyColor(myColor); - - // Set the current alpha-blending mode - renderer.SetBlendMode(myBlendMode); - - // Let the derived class render the object geometry - Render(target, renderer); -} - -} // namespace sf diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp index 8a7f64ca..6ea7ae15 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -451,7 +451,7 @@ Glyph Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c Page& page = myPages[characterSize]; // Find a good position for the new glyph into the texture - glyph.SubRect = FindGlyphRect(page, width + 2 * padding, height + 2 * padding); + glyph.TextureRect = FindGlyphRect(page, width + 2 * padding, height + 2 * padding); // Compute the glyph's bounding box glyph.Bounds.Left = bitmapGlyph->left - padding; @@ -492,10 +492,10 @@ Glyph Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c } // Write the pixels to the texture - unsigned int x = glyph.SubRect.Left + padding; - unsigned int y = glyph.SubRect.Top + padding; - unsigned int width = glyph.SubRect.Width - 2 * padding; - unsigned int height = glyph.SubRect.Height - 2 * padding; + unsigned int x = glyph.TextureRect.Left + padding; + unsigned int y = glyph.TextureRect.Top + padding; + unsigned int width = glyph.TextureRect.Width - 2 * padding; + unsigned int height = glyph.TextureRect.Height - 2 * padding; page.Texture.Update(&myPixelBuffer[0], width, height, x, y); } diff --git a/src/SFML/Graphics/GLCheck.hpp b/src/SFML/Graphics/GLCheck.hpp index 3be57e1a..560210c6 100644 --- a/src/SFML/Graphics/GLCheck.hpp +++ b/src/SFML/Graphics/GLCheck.hpp @@ -44,7 +44,7 @@ namespace priv #ifdef SFML_DEBUG // In debug mode, perform a test on every OpenGL call -#define GLCheck(call) ((call), sf::priv::GLCheckError(__FILE__, __LINE__)) + #define GLCheck(call) ((call), sf::priv::GLCheckError(__FILE__, __LINE__)) #else diff --git a/src/SFML/Graphics/RectangleShape.cpp b/src/SFML/Graphics/RectangleShape.cpp new file mode 100644 index 00000000..0d49192d --- /dev/null +++ b/src/SFML/Graphics/RectangleShape.cpp @@ -0,0 +1,76 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +RectangleShape::RectangleShape(const Vector2f& size) +{ + SetSize(size); +} + + +//////////////////////////////////////////////////////////// +void RectangleShape::SetSize(const Vector2f& size) +{ + mySize = size; + Update(); +} + + +//////////////////////////////////////////////////////////// +const Vector2f& RectangleShape::GetSize() const +{ + return mySize; +} + + +//////////////////////////////////////////////////////////// +unsigned int RectangleShape::GetPointsCount() const +{ + return 4; +} + + +//////////////////////////////////////////////////////////// +Vector2f RectangleShape::GetPoint(unsigned int index) const +{ + switch (index) + { + default: + case 0: return Vector2f(0, 0); + case 1: return Vector2f(mySize.x, 0); + case 2: return Vector2f(mySize.x, mySize.y); + case 3: return Vector2f(0, mySize.y); + } +} + +} // namespace sf diff --git a/src/SFML/Graphics/RenderStates.cpp b/src/SFML/Graphics/RenderStates.cpp new file mode 100644 index 00000000..83794db4 --- /dev/null +++ b/src/SFML/Graphics/RenderStates.cpp @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +const RenderStates RenderStates::Default; + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates() : +BlendMode(BlendAlpha), +Transform(), +Texture (NULL), +Shader (NULL) +{ +} + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates(const sf::Transform& transform) : +BlendMode(BlendAlpha), +Transform(transform), +Texture (NULL), +Shader (NULL) +{ +} + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates(sf::BlendMode blendMode) : +BlendMode(blendMode), +Transform(), +Texture (NULL), +Shader (NULL) +{ +} + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates(const sf::Texture* texture) : +BlendMode(BlendAlpha), +Transform(), +Texture (texture), +Shader (NULL) +{ +} + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates(const sf::Shader* shader) : +BlendMode(BlendAlpha), +Transform(), +Texture (NULL), +Shader (shader) +{ +} + + +//////////////////////////////////////////////////////////// +RenderStates::RenderStates(sf::BlendMode blendMode, const sf::Transform& transform, + const sf::Texture* texture, const sf::Shader* shader) : +BlendMode(blendMode), +Transform(transform), +Texture (texture), +Shader (shader) +{ +} + +} // namespace sf diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 60d3b58e..cea7386b 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -27,96 +27,37 @@ //////////////////////////////////////////////////////////// #include #include +#include +#include +#include +#include #include -#ifdef _MSC_VER - #pragma warning(disable : 4355) // "'this' : used in base member initializer list" -#endif - namespace sf { //////////////////////////////////////////////////////////// RenderTarget::RenderTarget() : -myRenderer (*this), -myStatesSaved (false), -myViewHasChanged(false) +myDefaultView(), +myView (), +myCache () { - } //////////////////////////////////////////////////////////// RenderTarget::~RenderTarget() { - // Nothing to do } //////////////////////////////////////////////////////////// void RenderTarget::Clear(const Color& color) -{ - if (Activate(true)) - myRenderer.Clear(color); -} - - -//////////////////////////////////////////////////////////// -void RenderTarget::Draw(const Drawable& object) { if (Activate(true)) { - // Update the projection matrix and viewport if the current view has changed - // Note: we do the changes here and not directly in SetView in order to gather - // rendering commands, which is safer in multithreaded environments - if (myViewHasChanged) - { - myRenderer.SetProjection(myCurrentView.GetMatrix()); - myRenderer.SetViewport(GetViewport(myCurrentView)); - myViewHasChanged = false; - } - - // Save the current render states - myRenderer.PushStates(); - - // Setup the shader - myRenderer.SetShader(NULL); - - // Let the object draw itself - object.Draw(*this, myRenderer); - - // Restore the previous render states - myRenderer.PopStates(); - } -} - - -//////////////////////////////////////////////////////////// -void RenderTarget::Draw(const Drawable& object, const Shader& shader) -{ - if (Activate(true)) - { - // Update the projection matrix and viewport if the current view has changed - // Note: we do the changes here and not directly in SetView in order to gather - // rendering commands, which is safer in multithreaded environments - if (myViewHasChanged) - { - myRenderer.SetProjection(myCurrentView.GetMatrix()); - myRenderer.SetViewport(GetViewport(myCurrentView)); - myViewHasChanged = false; - } - - // Save the current render states - myRenderer.PushStates(); - - // Setup the shader - myRenderer.SetShader(&shader); - - // Let the object draw itself - object.Draw(*this, myRenderer); - - // Restore the previous render states - myRenderer.PopStates(); + GLCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f)); + GLCheck(glClear(GL_COLOR_BUFFER_BIT)); } } @@ -124,16 +65,15 @@ void RenderTarget::Draw(const Drawable& object, const Shader& shader) //////////////////////////////////////////////////////////// void RenderTarget::SetView(const View& view) { - // Save it for later use - myCurrentView = view; - myViewHasChanged = true; + myView = view; + myCache.ViewChanged = true; } //////////////////////////////////////////////////////////// const View& RenderTarget::GetView() const { - return myCurrentView; + return myView; } @@ -175,35 +115,166 @@ Vector2f RenderTarget::ConvertCoords(unsigned int x, unsigned int y, const View& coords.y = 1.f - 2.f * (static_cast(y) - viewport.Top) / viewport.Height; // Then transform by the inverse of the view matrix - return view.GetInverseMatrix().Transform(coords); + return view.GetInverseTransform().TransformPoint(coords); } //////////////////////////////////////////////////////////// -void RenderTarget::SaveGLStates() +void RenderTarget::Draw(const Drawable& drawable, const RenderStates& states) { + drawable.Draw(*this, states); +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::Draw(const Vertex* vertices, unsigned int verticesCount, + PrimitiveType type, const RenderStates& states) +{ + // Nothing to draw? + if (!vertices || (verticesCount == 0)) + return; + if (Activate(true)) { - myRenderer.SaveGLStates(); - myStatesSaved = true; + // Check if the vertex count is low enough so that we can pre-transform them + bool useVertexCache = (verticesCount <= StatesCache::VertexCacheSize); + if (useVertexCache) + { + // Pre-transform the vertices and store them into the vertex cache + for (unsigned int i = 0; i < verticesCount; ++i) + { + Vertex& vertex = myCache.VertexCache[i]; + vertex.Position = states.Transform * vertices[i].Position; + vertex.Color = vertices[i].Color; + vertex.TexCoords = vertices[i].TexCoords; + } - // Restore the render states and the current view, for SFML rendering - myRenderer.Initialize(); - SetView(GetView()); + // Since vertices are transformed, we must use an identity transform to render them + if (!myCache.UseVertexCache) + ApplyTransform(Transform::Identity); + } + else + { + ApplyTransform(states.Transform); + } + + // Apply the view + if (myCache.ViewChanged) + ApplyCurrentView(); + + // Apply the blend mode + if (states.BlendMode != myCache.LastBlendMode) + ApplyBlendMode(states.BlendMode); + + // Apply the texture + Uint64 textureId = states.Texture ? states.Texture->myCacheId : 0; + if (textureId != myCache.LastTextureId) + ApplyTexture(states.Texture); + + // Apply the shader + if (states.Shader) + ApplyShader(states.Shader); + + // If we pre-transform the vertices, we must use our internal vertex cache + if (useVertexCache) + { + // ... and if we already used it previously, we don't need to set the pointers again + if (!myCache.UseVertexCache) + vertices = myCache.VertexCache; + else + vertices = NULL; + } + + // Setup the pointers to the vertices' components + if (vertices) + { + const char* data = reinterpret_cast(vertices); + GLCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0)); + GLCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8)); + GLCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12)); + } + + // Find the OpenGL primitive type + static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, + GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS}; + GLenum mode = modes[type]; + + // Draw the primitives + GLCheck(glDrawArrays(mode, 0, verticesCount)); + + // Unbind the shader, if any + if (states.Shader) + ApplyShader(NULL); + + // Update the cache + myCache.UseVertexCache = useVertexCache; } } //////////////////////////////////////////////////////////// -void RenderTarget::RestoreGLStates() +void RenderTarget::PushGLStates() { - if (myStatesSaved) + if (Activate(true)) { - if (Activate(true)) - { - myRenderer.RestoreGLStates(); - myStatesSaved = false; - } + GLCheck(glPushAttrib(GL_ALL_ATTRIB_BITS)); + GLCheck(glMatrixMode(GL_MODELVIEW)); + GLCheck(glPushMatrix()); + GLCheck(glMatrixMode(GL_PROJECTION)); + GLCheck(glPushMatrix()); + GLCheck(glMatrixMode(GL_TEXTURE)); + GLCheck(glPushMatrix()); + } + + ResetGLStates(); +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::PopGLStates() +{ + if (Activate(true)) + { + GLCheck(glPopAttrib()); + GLCheck(glMatrixMode(GL_PROJECTION)); + GLCheck(glPopMatrix()); + GLCheck(glMatrixMode(GL_MODELVIEW)); + GLCheck(glPopMatrix()); + GLCheck(glMatrixMode(GL_TEXTURE)); + GLCheck(glPopMatrix()); + } +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ResetGLStates() +{ + if (Activate(true)) + { + // Make sure that GLEW is initialized + priv::EnsureGlewInit(); + + // Define the default OpenGL states + GLCheck(glDisable(GL_LIGHTING)); + GLCheck(glDisable(GL_DEPTH_TEST)); + GLCheck(glEnable(GL_TEXTURE_2D)); + GLCheck(glEnable(GL_ALPHA_TEST)); + GLCheck(glEnable(GL_BLEND)); + GLCheck(glAlphaFunc(GL_GREATER, 0)); + GLCheck(glMatrixMode(GL_MODELVIEW)); + GLCheck(glEnableClientState(GL_VERTEX_ARRAY)); + GLCheck(glEnableClientState(GL_COLOR_ARRAY)); + GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + // Apply the default SFML states + ApplyBlendMode(BlendAlpha); + ApplyTransform(Transform::Identity); + ApplyTexture(NULL); + ApplyShader(NULL); + myCache.UseVertexCache = false; + + // Set the default view + SetView(GetView()); } } @@ -211,13 +282,135 @@ void RenderTarget::RestoreGLStates() //////////////////////////////////////////////////////////// void RenderTarget::Initialize() { - // Setup the default view + // Setup the default and current views myDefaultView.Reset(FloatRect(0, 0, static_cast(GetWidth()), static_cast(GetHeight()))); - SetView(myDefaultView); + myView = myDefaultView; - // Initialize the renderer - if (Activate(true)) - myRenderer.Initialize(); + // Initialize the default OpenGL render-states + ResetGLStates(); +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ApplyCurrentView() +{ + // Set the viewport + IntRect viewport = GetViewport(myView); + int top = GetHeight() - (viewport.Top + viewport.Height); + GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height)); + + // Set the projection matrix + GLCheck(glMatrixMode(GL_PROJECTION)); + GLCheck(glLoadMatrixf(myView.GetTransform().GetMatrix())); + + // Go back to model-view mode + GLCheck(glMatrixMode(GL_MODELVIEW)); + + myCache.ViewChanged = false; +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ApplyBlendMode(BlendMode mode) +{ + switch (mode) + { + // Alpha blending + // glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target + // is a RenderTexture -- in this case the alpha value must be written directly to the target buffer + default : + case BlendAlpha : + if (GLEW_EXT_blend_func_separate) + GLCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); + else + GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + break; + + // Additive blending + case BlendAdd : + GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE)); + break; + + // Multiplicative blending + case BlendMultiply : + GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO)); + break; + + // No blending + case BlendNone : + GLCheck(glBlendFunc(GL_ONE, GL_ZERO)); + break; + } + + myCache.LastBlendMode = mode; +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ApplyTransform(const Transform& transform) +{ + // No need to call glMatrixMode(GL_MODELVIEW), it is always the + // current mode (for optimization purpose, since it's the most used) + GLCheck(glLoadMatrixf(transform.GetMatrix())); +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ApplyTexture(const Texture* texture) +{ + if (texture) + texture->Bind(Texture::Pixels); + else + GLCheck(glBindTexture(GL_TEXTURE_2D, 0)); + + myCache.LastTextureId = texture ? texture->myCacheId : 0; +} + + +//////////////////////////////////////////////////////////// +void RenderTarget::ApplyShader(const Shader* shader) +{ + if (shader) + shader->Bind(); + else + GLCheck(glUseProgramObjectARB(0)); } } // namespace sf + + +//////////////////////////////////////////////////////////// +// Render states caching strategies +// +// * View +// If SetView was called since last draw, the projection +// matrix is updated. We don't need more, the view doesn't +// change frequently. +// +// * Transform +// The transform matrix is usually expensive because each +// entity will most likely use a different transform. This can +// lead, in worst case, to changing it every 4 vertices. +// To avoid that, when the vertex count is low enough, we +// pre-transform them and therefore use an identity transform +// to render them. +// +// * Blending mode +// It's a simple integral value, so we can easily check +// whether the value to apply is the same as before or not. +// +// * Texture +// Storing the pointer or OpenGL ID of the last used texture +// is not enough; if the sf::Texture instance is destroyed, +// both the pointer and the OpenGL ID might be recycled in +// a new texture instance. We need to use our own unique +// identifier system to ensure consistent caching. +// +// * Shader +// Shaders are very hard to optimize, because they have +// parameters that can be hard (if not impossible) to track, +// like matrices or textures. The only optimization that we +// do is that we avoid setting a null shader if there was +// already none for the previous draw. +// +//////////////////////////////////////////////////////////// diff --git a/src/SFML/Graphics/RenderTextureImplDefault.cpp b/src/SFML/Graphics/RenderTextureImplDefault.cpp index 7cffc63c..481eed64 100644 --- a/src/SFML/Graphics/RenderTextureImplDefault.cpp +++ b/src/SFML/Graphics/RenderTextureImplDefault.cpp @@ -27,6 +27,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include @@ -77,6 +78,9 @@ bool RenderTextureImplDefault::Activate(bool active) //////////////////////////////////////////////////////////// void RenderTextureImplDefault::UpdateTexture(unsigned int textureId) { + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Copy the rendered pixels to the texture GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); diff --git a/src/SFML/Graphics/RenderTextureImplFBO.cpp b/src/SFML/Graphics/RenderTextureImplFBO.cpp index 326452ae..d7ded0de 100644 --- a/src/SFML/Graphics/RenderTextureImplFBO.cpp +++ b/src/SFML/Graphics/RenderTextureImplFBO.cpp @@ -83,7 +83,7 @@ bool RenderTextureImplFBO::IsAvailable() //////////////////////////////////////////////////////////// bool RenderTextureImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer) { - //Create the context + // Create the context myContext = new Context; // Create the framebuffer object diff --git a/src/SFML/Graphics/Renderer.cpp b/src/SFML/Graphics/Renderer.cpp deleted file mode 100644 index 82a60a54..00000000 --- a/src/SFML/Graphics/Renderer.cpp +++ /dev/null @@ -1,348 +0,0 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include - - -namespace sf -{ -//////////////////////////////////////////////////////////// -Renderer::Renderer(RenderTarget& target) : -myTarget (target), -myTextureIsValid (false), -myShaderIsValid (false), -myBlendModeIsValid(false), -myViewportIsValid (false) -{ - myStates = &myStatesStack[0]; -} - - -//////////////////////////////////////////////////////////// -void Renderer::Initialize() -{ - // Default render states - GLCheck(glDisable(GL_LIGHTING)); - GLCheck(glDisable(GL_DEPTH_TEST)); - GLCheck(glEnable(GL_TEXTURE_2D)); - GLCheck(glEnable(GL_ALPHA_TEST)); - GLCheck(glAlphaFunc(GL_GREATER, 0)); - - // Default transform matrices - GLCheck(glMatrixMode(GL_MODELVIEW)); - GLCheck(glLoadIdentity()); - GLCheck(glMatrixMode(GL_PROJECTION)); - GLCheck(glLoadIdentity()); - - // Invalidate the cached SFML states - myTextureIsValid = false; - myShaderIsValid = false; - myBlendModeIsValid = false; - myViewportIsValid = false; -} - - -//////////////////////////////////////////////////////////// -void Renderer::SaveGLStates() -{ - // Save render states - GLCheck(glPushAttrib(GL_ALL_ATTRIB_BITS)); - - // Save matrices - GLCheck(glMatrixMode(GL_MODELVIEW)); - GLCheck(glPushMatrix()); - GLCheck(glMatrixMode(GL_PROJECTION)); - GLCheck(glPushMatrix()); -} - - -//////////////////////////////////////////////////////////// -void Renderer::RestoreGLStates() -{ - // Restore render states - GLCheck(glPopAttrib()); - - // Restore matrices - GLCheck(glMatrixMode(GL_PROJECTION)); - GLCheck(glPopMatrix()); - GLCheck(glMatrixMode(GL_MODELVIEW)); - GLCheck(glPopMatrix()); -} - - -//////////////////////////////////////////////////////////// -void Renderer::Clear(const Color& color) -{ - GLCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f)); - GLCheck(glClear(GL_COLOR_BUFFER_BIT)); -} - - -//////////////////////////////////////////////////////////// -void Renderer::PushStates() -{ - myStates++; - *myStates = *(myStates - 1); -} - - -//////////////////////////////////////////////////////////// -void Renderer::PopStates() -{ - myStates--; -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetModelView(const Matrix3& matrix) -{ - myStates->modelView = matrix; -} - - -//////////////////////////////////////////////////////////// -void Renderer::ApplyModelView(const Matrix3& matrix) -{ - myStates->modelView = myStates->modelView * matrix; -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetProjection(const Matrix3& matrix) -{ - // Apply it immediately (this one is not critical for performances) - GLCheck(glMatrixMode(GL_PROJECTION)); - GLCheck(glLoadMatrixf(matrix.Get4x4Elements())); -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetColor(const Color& color) -{ - myStates->r = color.r / 255.f; - myStates->g = color.g / 255.f; - myStates->b = color.b / 255.f; - myStates->a = color.a / 255.f; -} - - -//////////////////////////////////////////////////////////// -void Renderer::ApplyColor(const Color& color) -{ - myStates->r *= color.r / 255.f; - myStates->g *= color.g / 255.f; - myStates->b *= color.b / 255.f; - myStates->a *= color.a / 255.f; -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetViewport(const IntRect& viewport) -{ - if ((viewport.Left != myViewport.Left) || (viewport.Width != myViewport.Width) || - (viewport.Top != myViewport.Top) || (viewport.Height != myViewport.Height) || - !myViewportIsValid) - { - // Revert the Y axis to match the OpenGL convention - int top = myTarget.GetHeight() - (viewport.Top + viewport.Height); - - // Apply the new viewport - GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height)); - - // Store it - myViewport = viewport; - myViewportIsValid = true; - } -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetBlendMode(Blend::Mode mode) -{ - if ((mode != myBlendMode) || !myBlendModeIsValid) - { - // Apply the new blending mode - if (mode == Blend::None) - { - GLCheck(glDisable(GL_BLEND)); - } - else - { - GLCheck(glEnable(GL_BLEND)); - - switch (mode) - { - // Alpha blending - // glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target - // is a RenderTexture -- in this case the alpha value must be written directly to the target buffer - default : - case Blend::Alpha : - if (GLEW_EXT_blend_func_separate) - GLCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); - else - GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - break; - - // Additive blending - case Blend::Add : - GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE)); - break; - - // Multiplicative blending - case Blend::Multiply : - GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO)); - break; - } - } - - // Store it - myBlendMode = mode; - myBlendModeIsValid = true; - } -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetTexture(const Texture* texture) -{ - if ((texture != myTexture) || (texture && (texture->myTexture != myTextureId)) || !myTextureIsValid) - { - // Apply the new texture - if (texture) - texture->Bind(); - else - GLCheck(glBindTexture(GL_TEXTURE_2D, 0)); - - // Store it - myTexture = texture; - myTextureId = texture ? texture->myTexture : 0; - myTextureIsValid = true; - } -} - - -//////////////////////////////////////////////////////////// -void Renderer::SetShader(const Shader* shader) -{ - if ((shader != myShader) || !myShaderIsValid) - { - if (Shader::IsAvailable()) // to avoid calling possibly unsupported functions - { - // Apply the new shader - if (shader) - shader->Bind(); - else - GLCheck(glUseProgramObjectARB(0)); - - // Store it - myShader = shader; - myShaderIsValid = true; - } - } - else if (shader && myShaderIsValid) - { - // If the shader was already the current one, make sure that - // it is synchronized (in case it was modified since last use) - shader->Use(); - } -} - - -//////////////////////////////////////////////////////////// -void Renderer::Begin(PrimitiveType type) -{ - // Begin rendering - switch (type) - { - case TriangleList : glBegin(GL_TRIANGLES); break; - case TriangleStrip : glBegin(GL_TRIANGLE_STRIP); break; - case TriangleFan : glBegin(GL_TRIANGLE_FAN); break; - case QuadList : glBegin(GL_QUADS); break; - default: break; - } -} - - -//////////////////////////////////////////////////////////// -void Renderer::End() -{ - // End rendering - glEnd(); -} - - -//////////////////////////////////////////////////////////// -void Renderer::AddVertex(float x, float y) -{ - ProcessVertex(x, y, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f); -} - - -//////////////////////////////////////////////////////////// -void Renderer::AddVertex(float x, float y, float u, float v) -{ - ProcessVertex(x, y, u, v, 1.f, 1.f, 1.f, 1.f); -} - - -//////////////////////////////////////////////////////////// -void Renderer::AddVertex(float x, float y, const Color& color) -{ - ProcessVertex(x, y, 0.f, 0.f, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); -} - - -//////////////////////////////////////////////////////////// -void Renderer::AddVertex(float x, float y, float u, float v, const Color& color) -{ - ProcessVertex(x, y, u, v, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); -} - - -//////////////////////////////////////////////////////////// -void Renderer::ProcessVertex(float x, float y, float u, float v, float r, float g, float b, float a) -{ - // Transform the vertex position by the current model-view matrix - Vector2f position = myStates->modelView.Transform(Vector2f(x, y)); - - // Modulate the vertex color with the current global color - r *= myStates->r; - g *= myStates->g; - b *= myStates->b; - a *= myStates->a; - - // Render the vertex - glColor4f(r, g, b, a); - glTexCoord2f(u, v); - glVertex2f(position.x, position.y); -} - -} // namespace sf diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index 82d91ffc..8847b0fa 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -27,6 +27,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -46,30 +47,50 @@ namespace GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits)); return maxUnits; } + + // Read the contents of a file into an array of char + bool GetFileContents(const std::string& filename, std::vector& buffer) + { + std::ifstream file(filename.c_str(), std::ios_base::binary); + if (file) + { + file.seekg(0, std::ios_base::end); + std::streamsize size = file.tellg(); + file.seekg(0, std::ios_base::beg); + buffer.resize(size); + file.read(&buffer[0], size); + buffer.push_back('\0'); + return true; + } + else + { + return false; + } + } + + // Read the contents of a stream into an array of char + bool GetStreamContents(sf::InputStream& stream, std::vector& buffer) + { + sf::Int64 size = stream.GetSize(); + buffer.resize(static_cast(size)); + sf::Int64 read = stream.Read(&buffer[0], size); + buffer.push_back('\0'); + return read == size; + } } namespace sf { +//////////////////////////////////////////////////////////// +Shader::CurrentTextureType Shader::CurrentTexture; + + //////////////////////////////////////////////////////////// Shader::Shader() : myShaderProgram (0), myCurrentTexture(-1) { - -} - - -//////////////////////////////////////////////////////////// -Shader::Shader(const Shader& copy) : -myShaderProgram (0), -myCurrentTexture(copy.myCurrentTexture), -myTextures (copy.myTextures), -myFragmentShader(copy.myFragmentShader) -{ - // Create the shaders and the program - if (copy.myShaderProgram) - CompileProgram(); } @@ -85,48 +106,107 @@ Shader::~Shader() //////////////////////////////////////////////////////////// -bool Shader::LoadFromFile(const std::string& filename) +bool Shader::LoadFromFile(const std::string& filename, Type type) { - // Open the file - std::ifstream file(filename.c_str()); - if (!file) + // Read the file + std::vector shader; + if (!GetFileContents(filename, shader)) { Err() << "Failed to open shader file \"" << filename << "\"" << std::endl; return false; } - // Read the shader code from the file - myFragmentShader.clear(); - std::string line; - while (std::getline(file, line)) - myFragmentShader += line + "\n"; - - // Create the shaders and the program - return CompileProgram(); + // Compile the shader program + if (type == Vertex) + return CompileProgram(&shader[0], NULL); + else + return CompileProgram(NULL, &shader[0]); } //////////////////////////////////////////////////////////// -bool Shader::LoadFromMemory(const std::string& shader) +bool Shader::LoadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename) { - // Save the shader code - myFragmentShader = shader; + // Read the vertex shader file + std::vector vertexShader; + if (!GetFileContents(vertexShaderFilename, vertexShader)) + { + Err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl; + return false; + } - // Create the shaders and the program - return CompileProgram(); + // Read the fragment shader file + std::vector fragmentShader; + if (!GetFileContents(fragmentShaderFilename, fragmentShader)) + { + Err() << "Failed to open fragment shader file \"" << fragmentShaderFilename << "\"" << std::endl; + return false; + } + + // Compile the shader program + return CompileProgram(&vertexShader[0], &fragmentShader[0]); } //////////////////////////////////////////////////////////// -bool Shader::LoadFromStream(InputStream& stream) +bool Shader::LoadFromMemory(const std::string& shader, Type type) +{ + // Compile the shader program + if (type == Vertex) + return CompileProgram(shader.c_str(), NULL); + else + return CompileProgram(NULL, shader.c_str()); +} + + +//////////////////////////////////////////////////////////// +bool Shader::LoadFromMemory(const std::string& vertexShader, const std::string& fragmentShader) +{ + // Compile the shader program + return CompileProgram(vertexShader.c_str(), fragmentShader.c_str()); +} + + +//////////////////////////////////////////////////////////// +bool Shader::LoadFromStream(InputStream& stream, Type type) { // Read the shader code from the stream - std::vector buffer(static_cast(stream.GetSize())); - Int64 read = stream.Read(&buffer[0], buffer.size()); - myFragmentShader.assign(&buffer[0], &buffer[0] + read); + std::vector shader; + if (!GetStreamContents(stream, shader)) + { + Err() << "Failed to read shader from stream" << std::endl; + return false; + } - // Create the shaders and the program - return CompileProgram(); + // Compile the shader program + if (type == Vertex) + return CompileProgram(&shader[0], NULL); + else + return CompileProgram(NULL, &shader[0]); +} + + +//////////////////////////////////////////////////////////// +bool Shader::LoadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream) +{ + // Read the vertex shader code from the stream + std::vector vertexShader; + if (!GetStreamContents(vertexShaderStream, vertexShader)) + { + Err() << "Failed to read vertex shader from stream" << std::endl; + return false; + } + + // Read the fragment shader code from the stream + std::vector fragmentShader; + if (!GetStreamContents(fragmentShaderStream, fragmentShader)) + { + Err() << "Failed to read fragment shader from stream" << std::endl; + return false; + } + + // Compile the shader program + return CompileProgram(&vertexShader[0], &fragmentShader[0]); } @@ -241,7 +321,38 @@ void Shader::SetParameter(const std::string& name, const Vector3f& v) //////////////////////////////////////////////////////////// -void Shader::SetTexture(const std::string& name, const Texture& texture) +void Shader::SetParameter(const std::string& name, const Color& color) +{ + SetParameter(name, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); +} + + +//////////////////////////////////////////////////////////// +void Shader::SetParameter(const std::string& name, const sf::Transform& transform) +{ + 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(glUniformMatrix4fvARB(location, 1, GL_FALSE, transform.GetMatrix())); + else + Err() << "Parameter \"" << name << "\" not found in shader" << std::endl; + + // Disable program + GLCheck(glUseProgramObjectARB(program)); + } +} + + +//////////////////////////////////////////////////////////// +void Shader::SetParameter(const std::string& name, const Texture& texture) { if (myShaderProgram) { @@ -279,7 +390,7 @@ void Shader::SetTexture(const std::string& name, const Texture& texture) //////////////////////////////////////////////////////////// -void Shader::SetCurrentTexture(const std::string& name) +void Shader::SetParameter(const std::string& name, CurrentTextureType) { if (myShaderProgram) { @@ -322,20 +433,6 @@ void Shader::Unbind() const } -//////////////////////////////////////////////////////////// -Shader& Shader::operator =(const Shader& right) -{ - Shader temp(right); - - std::swap(myShaderProgram, temp.myShaderProgram); - std::swap(myCurrentTexture, temp.myCurrentTexture); - std::swap(myTextures, temp.myTextures); - std::swap(myFragmentShader, temp.myFragmentShader); - - return *this; -} - - //////////////////////////////////////////////////////////// bool Shader::IsAvailable() { @@ -352,7 +449,7 @@ bool Shader::IsAvailable() //////////////////////////////////////////////////////////// -bool Shader::CompileProgram() +bool Shader::CompileProgram(const char* vertexShaderCode, const char* fragmentShaderCode) { EnsureGlContext(); @@ -368,74 +465,73 @@ bool Shader::CompileProgram() 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) + // Create the vertex shader if needed + if (vertexShaderCode) { - char log[1024]; - GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log)); - Err() << "Failed to compile shader:" << std::endl - << log << std::endl; + // 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)); - 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)); + // 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)); - // We can now delete the shaders - GLCheck(glDeleteObjectARB(vertexShader)); - GLCheck(glDeleteObjectARB(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)); - // Get link log + // Check the link log + GLint success; 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 @@ -466,11 +562,4 @@ void Shader::BindTextures() const GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB)); } - -//////////////////////////////////////////////////////////// -void Shader::Use() const -{ - BindTextures(); -} - } // namespace sf diff --git a/src/SFML/Graphics/Shape.cpp b/src/SFML/Graphics/Shape.cpp index ed80496f..de585e92 100644 --- a/src/SFML/Graphics/Shape.cpp +++ b/src/SFML/Graphics/Shape.cpp @@ -26,365 +26,270 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include +#include +#include #include +//////////////////////////////////////////////////////////// +// Private data +//////////////////////////////////////////////////////////// +namespace +{ + // Compute the normal of a segment + sf::Vector2f ComputeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2) + { + sf::Vector2f normal(p1.y - p2.y, p2.x - p1.x); + float length = std::sqrt(normal.x * normal.x + normal.y * normal.y); + if (length != 0.f) + normal /= length; + return normal; + } +} + + namespace sf { //////////////////////////////////////////////////////////// -Shape::Shape() : -myOutline (0.f), -myIsFillEnabled (true), -myIsOutlineEnabled(true), -myIsCompiled (false) +Shape::~Shape() { - // Put a placeholder for the center of the shape - myPoints.push_back(Point()); } //////////////////////////////////////////////////////////// -void Shape::AddPoint(float x, float y, const Color& color, const Color& outlineColor) +void Shape::SetTexture(const Texture* texture, bool resetRect) { - AddPoint(Vector2f(x, y), color, outlineColor); + // Recompute the texture area if requested, or if there was no texture before + if (texture && (resetRect || !myTexture)) + SetTextureRect(IntRect(0, 0, texture->GetWidth(), texture->GetHeight())); + + // Assign the new texture + myTexture = texture; } //////////////////////////////////////////////////////////// -void Shape::AddPoint(const Vector2f& position, const Color& color, const Color& outlineColor) +const Texture* Shape::GetTexture() const { - myPoints.push_back(Point(position, color, outlineColor)); - myIsCompiled = false; + return myTexture; } //////////////////////////////////////////////////////////// -unsigned int Shape::GetPointsCount() const +void Shape::SetTextureRect(const IntRect& rect) { - return static_cast(myPoints.size() - 1); + myTextureRect = rect; + UpdateTexCoords(); } //////////////////////////////////////////////////////////// -void Shape::EnableFill(bool enable) +const IntRect& Shape::GetTextureRect() const { - myIsFillEnabled = enable; + return myTextureRect; } //////////////////////////////////////////////////////////// -void Shape::EnableOutline(bool enable) +void Shape::SetFillColor(const Color& color) { - myIsOutlineEnabled = enable; + myFillColor = color; + UpdateFillColors(); } //////////////////////////////////////////////////////////// -void Shape::SetPointPosition(unsigned int index, const Vector2f& position) +const Color& Shape::GetFillColor() const { - myPoints[index + 1].Position = position; - myIsCompiled = false; + return myFillColor; } //////////////////////////////////////////////////////////// -void Shape::SetPointPosition(unsigned int index, float x, float y) +void Shape::SetOutlineColor(const Color& color) { - SetPointPosition(index, Vector2f(x, y)); + myOutlineColor = color; + UpdateOutlineColors(); } //////////////////////////////////////////////////////////// -void Shape::SetPointColor(unsigned int index, const Color& color) +const Color& Shape::GetOutlineColor() const { - myPoints[index + 1].Col = color; - myIsCompiled = false; -} - - -//////////////////////////////////////////////////////////// -void Shape::SetPointOutlineColor(unsigned int index, const Color& color) -{ - myPoints[index + 1].OutlineCol = color; - myIsCompiled = false; + return myOutlineColor; } //////////////////////////////////////////////////////////// void Shape::SetOutlineThickness(float thickness) { - myOutline = thickness; -} - - -//////////////////////////////////////////////////////////// -const Vector2f& Shape::GetPointPosition(unsigned int index) const -{ - return myPoints[index + 1].Position; -} - - -//////////////////////////////////////////////////////////// -const Color& Shape::GetPointColor(unsigned int index) const -{ - return myPoints[index + 1].Col; -} - - -//////////////////////////////////////////////////////////// -const Color& Shape::GetPointOutlineColor(unsigned int index) const -{ - return myPoints[index + 1].OutlineCol; + myOutlineThickness = thickness; + Update(); // recompute everything because the whole shape must be offset } //////////////////////////////////////////////////////////// float Shape::GetOutlineThickness() const { - return myOutline; + return myOutlineThickness; } //////////////////////////////////////////////////////////// -Shape Shape::Line(float p1x, float p1y, float p2x, float p2y, float thickness, const Color& color, float outline, const Color& outlineColor) +FloatRect Shape::GetLocalBounds() const { - Vector2f p1(p1x, p1y); - Vector2f p2(p2x, p2y); - - return Shape::Line(p1, p2, thickness, color, outline, outlineColor); + return myBounds; } //////////////////////////////////////////////////////////// -Shape Shape::Line(const Vector2f& p1, const Vector2f& p2, float thickness, const Color& color, float outline, const Color& outlineColor) +FloatRect Shape::GetGlobalBounds() const { - // Compute the extrusion direction - Vector2f normal; - ComputeNormal(p1, p2, normal); - normal *= thickness / 2; - - // Create the shape's points - Shape shape; - shape.AddPoint(p1 - normal, color, outlineColor); - shape.AddPoint(p2 - normal, color, outlineColor); - shape.AddPoint(p2 + normal, color, outlineColor); - shape.AddPoint(p1 + normal, color, outlineColor); - shape.SetOutlineThickness(outline); - - // Compile it - shape.Compile(); - - return shape; + return GetTransform().TransformRect(GetLocalBounds()); } //////////////////////////////////////////////////////////// -Shape Shape::Rectangle(float left, float top, float width, float height, const Color& color, float outline, const Color& outlineColor) +Shape::Shape() : +myTexture (NULL), +myTextureRect (), +myFillColor (255, 255, 255), +myOutlineColor (255, 255, 255), +myOutlineThickness(0), +myVertices (TrianglesFan), +myOutlineVertices (TrianglesStrip), +myInsideBounds (), +myBounds () { - // Create the shape's points - Shape shape; - shape.AddPoint(Vector2f(left, top), color, outlineColor); - shape.AddPoint(Vector2f(left + width, top), color, outlineColor); - shape.AddPoint(Vector2f(left + width, top + height), color, outlineColor); - shape.AddPoint(Vector2f(left, top + height), color, outlineColor); - shape.SetOutlineThickness(outline); - - // Compile it - shape.Compile(); - - return shape; } //////////////////////////////////////////////////////////// -Shape Shape::Rectangle(const FloatRect& rectangle, const Color& color, float outline, const Color& outlineColor) +void Shape::Update() { - return Shape::Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, color, outline, outlineColor); -} - - -//////////////////////////////////////////////////////////// -Shape Shape::Circle(float x, float y, float radius, const Color& color, float outline, const Color& outlineColor) -{ - return Shape::Circle(Vector2f(x, y), radius, color, outline, outlineColor); -} - - -//////////////////////////////////////////////////////////// -Shape Shape::Circle(const Vector2f& center, float radius, const Color& color, float outline, const Color& outlineColor) -{ - static const int nbSegments = 40; - - // Create the points set - Shape shape; - for (int i = 0; i < nbSegments; ++i) + // Get the total number of points of the shape + unsigned int count = GetPointsCount(); + if (count < 3) { - float angle = i * 2 * 3.141592654f / nbSegments; - Vector2f offset(std::cos(angle), std::sin(angle)); - - shape.AddPoint(center + offset * radius, color, outlineColor); - } - - // Compile it - shape.SetOutlineThickness(outline); - shape.Compile(); - - return shape; -} - - -//////////////////////////////////////////////////////////// -void Shape::Render(RenderTarget&, Renderer& renderer) const -{ - // Make sure the shape has at least 3 points (4 if we count the center) - if (myPoints.size() < 4) + myVertices.Resize(0); + myOutlineVertices.Resize(0); return; - - // Make sure the shape is compiled - if (!myIsCompiled) - const_cast(this)->Compile(); - - // Shapes only use color, no texture - renderer.SetTexture(NULL); - - // Draw the shape - if (myIsFillEnabled) - { - if (myPoints.size() == 4) - { - // Special case of a triangle - renderer.Begin(Renderer::TriangleList); - renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col); - renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col); - renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col); - renderer.End(); - } - else if (myPoints.size() == 5) - { - // Special case of a quad - renderer.Begin(Renderer::TriangleStrip); - renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col); - renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col); - renderer.AddVertex(myPoints[4].Position.x, myPoints[4].Position.y, myPoints[4].Col); - renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col); - renderer.End(); - } - else - { - renderer.Begin(Renderer::TriangleFan); - - // General case of a convex polygon - for (std::vector::const_iterator i = myPoints.begin(); i != myPoints.end(); ++i) - renderer.AddVertex(i->Position.x, i->Position.y, i->Col); - - // Close the shape by duplicating the first point at the end - const Point& first = myPoints[1]; - renderer.AddVertex(first.Position.x, first.Position.y, first.Col); - - renderer.End(); - } } - // Draw the outline - if (myIsOutlineEnabled && (myOutline != 0)) + myVertices.Resize(count + 2); // + 2 for center and repeated first point + + // Position + for (unsigned int i = 0; i < count; ++i) + myVertices[i + 1].Position = GetPoint(i); + myVertices[count + 1].Position = myVertices[1].Position; + + // Update the bounding rectangle + myVertices[0] = myVertices[1]; // so that the result of GetBounds() is correct + myInsideBounds = myVertices.GetBounds(); + + // Compute the center and make it the first vertex + myVertices[0].Position.x = myInsideBounds.Left + myInsideBounds.Width / 2; + myVertices[0].Position.y = myInsideBounds.Top + myInsideBounds.Height / 2; + + // Color + UpdateFillColors(); + + // Texture coordinates + UpdateTexCoords(); + + // Outline + UpdateOutline(); +} + + +//////////////////////////////////////////////////////////// +void Shape::Draw(RenderTarget& target, RenderStates states) const +{ + states.Transform *= GetTransform(); + + // Render the inside + if (myFillColor.a > 0) { - renderer.Begin(Renderer::TriangleStrip); + states.Texture = myTexture; + target.Draw(myVertices, states); + } - for (std::vector::const_iterator i = myPoints.begin() + 1; i != myPoints.end(); ++i) - { - Vector2f point1 = i->Position; - Vector2f point2 = i->Position + i->Normal * myOutline; - renderer.AddVertex(point1.x, point1.y, i->OutlineCol); - renderer.AddVertex(point2.x, point2.y, i->OutlineCol); - } - - // Close the shape by duplicating the first point at the end - const Point& first = myPoints[1]; - Vector2f point1 = first.Position; - Vector2f point2 = first.Position + first.Normal * myOutline; - renderer.AddVertex(point1.x, point1.y, first.OutlineCol); - renderer.AddVertex(point2.x, point2.y, first.OutlineCol); - - renderer.End(); + // Render the outline + if ((myOutlineColor.a > 0) && (myOutlineThickness > 0)) + { + states.Texture = NULL; + target.Draw(myOutlineVertices, states); } } //////////////////////////////////////////////////////////// -void Shape::Compile() +void Shape::UpdateFillColors() { - // Compute the center - float nbPoints = static_cast(myPoints.size() - 1); - float r = 0, g = 0, b = 0, a = 0; - Point center(Vector2f(0, 0), Color(0, 0, 0, 0)); - for (std::size_t i = 1; i < myPoints.size(); ++i) - { - center.Position += myPoints[i].Position; - r += myPoints[i].Col.r; - g += myPoints[i].Col.g; - b += myPoints[i].Col.b; - a += myPoints[i].Col.a; - } - center.Position /= nbPoints; - center.Col.r = static_cast(r / nbPoints); - center.Col.g = static_cast(g / nbPoints); - center.Col.b = static_cast(b / nbPoints); - center.Col.a = static_cast(a / nbPoints); - myPoints[0] = center; + for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i) + myVertices[i].Color = myFillColor; +} - // Compute the outline - for (std::size_t i = 1; i < myPoints.size(); ++i) + +//////////////////////////////////////////////////////////// +void Shape::UpdateTexCoords() +{ + for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i) { + float xratio = (myVertices[i].Position.x - myInsideBounds.Left) / myInsideBounds.Width; + float yratio = (myVertices[i].Position.y - myInsideBounds.Top) / myInsideBounds.Height; + myVertices[i].TexCoords.x = myTextureRect.Left + myTextureRect.Width * xratio; + myVertices[i].TexCoords.y = myTextureRect.Top + myTextureRect.Height * yratio; + } +} + + +//////////////////////////////////////////////////////////// +void Shape::UpdateOutline() +{ + unsigned int count = myVertices.GetVerticesCount() - 2; + myOutlineVertices.Resize((count + 1) * 2); + + for (unsigned int i = 0; i < count; ++i) + { + unsigned int index = i + 1; + // Get the two segments shared by the current point - Point& p0 = (i == 1) ? myPoints[myPoints.size() - 1] : myPoints[i - 1]; - Point& p1 = myPoints[i]; - Point& p2 = (i == myPoints.size() - 1) ? myPoints[1] : myPoints[i + 1]; + Vector2f p0 = (i == 0) ? myVertices[count].Position : myVertices[index - 1].Position; + Vector2f p1 = myVertices[index].Position; + Vector2f p2 = myVertices[index + 1].Position; // Compute their normal - Vector2f normal1, normal2; - if (!ComputeNormal(p0.Position, p1.Position, normal1) || !ComputeNormal(p1.Position, p2.Position, normal2)) - continue; + Vector2f n1 = ComputeNormal(p0, p1); + Vector2f n2 = ComputeNormal(p1, p2); - // Add them to get the extrusion direction - float factor = 1.f + (normal1.x * normal2.x + normal1.y * normal2.y); - p1.Normal = (normal1 + normal2) / factor; + // Combine them to get the extrusion direction + float factor = 1.f + (n1.x * n2.x + n1.y * n2.y); + Vector2f normal = -(n1 + n2) / factor; - // Make sure it points towards the outside of the shape - float dot = (p1.Position.x - center.Position.x) * p1.Normal.x + (p1.Position.y - center.Position.y) * p1.Normal.y; - if (dot < 0) - p1.Normal = -p1.Normal; + // Update the outline points + myOutlineVertices[i * 2 + 0].Position = p1; + myOutlineVertices[i * 2 + 1].Position = p1 + normal * myOutlineThickness; } - myIsCompiled = true; + // Duplicate the first point at the end, to close the outline + myOutlineVertices[count * 2 + 0].Position = myOutlineVertices[0].Position; + myOutlineVertices[count * 2 + 1].Position = myOutlineVertices[1].Position; + + // Update outline colors + UpdateOutlineColors(); + + // Update the shape's bounds + myBounds = myOutlineVertices.GetBounds(); } //////////////////////////////////////////////////////////// -bool Shape::ComputeNormal(const Vector2f& p1, const Vector2f& p2, Vector2f& normal) +void Shape::UpdateOutlineColors() { - normal.x = p1.y - p2.y; - normal.y = p2.x - p1.x; - - float len = std::sqrt(normal.x * normal.x + normal.y * normal.y); - if (len == 0.f) - return false; - - normal.x /= len; - normal.y /= len; - - return true; -} - - -//////////////////////////////////////////////////////////// -Shape::Point::Point(const Vector2f& position, const Color& color, const Color& outlineColor) : -Position (position), -Normal (0.f, 0.f), -Col (color), -OutlineCol(outlineColor) -{ - + for (unsigned int i = 0; i < myOutlineVertices.GetVerticesCount(); ++i) + myOutlineVertices[i].Color = myOutlineColor; } } // namespace sf diff --git a/src/SFML/Graphics/Sprite.cpp b/src/SFML/Graphics/Sprite.cpp index 6518dc46..cb8b1db0 100644 --- a/src/SFML/Graphics/Sprite.cpp +++ b/src/SFML/Graphics/Sprite.cpp @@ -27,48 +27,44 @@ //////////////////////////////////////////////////////////// #include #include -#include -#include +#include namespace sf { //////////////////////////////////////////////////////////// Sprite::Sprite() : -Drawable (), -myTexture (NULL), -mySubRect (0, 0, 1, 1), -myIsFlippedX(false), -myIsFlippedY(false) +myTexture (NULL), +myTextureRect(0, 0, 0, 0) { - } //////////////////////////////////////////////////////////// Sprite::Sprite(const Texture& texture) : -Drawable (), -myTexture (NULL), -mySubRect (0, 0, 1, 1), -myIsFlippedX(false), -myIsFlippedY(false) +myTexture (NULL), +myTextureRect(0, 0, 0, 0) { SetTexture(texture); } //////////////////////////////////////////////////////////// -void Sprite::SetTexture(const Texture& texture, bool adjustToNewSize) +Sprite::Sprite(const Texture& texture, const IntRect& rectangle) : +myTexture (NULL), +myTextureRect(0, 0, 0, 0) { - // If there was no valid texture before, force adjusting to the new texture size - if (!myTexture) - adjustToNewSize = true; + SetTexture(texture); + SetTextureRect(rectangle); +} - // If we want to adjust the size and the new texture is valid, we adjust the source rectangle - if (adjustToNewSize && (texture.GetWidth() > 0) && (texture.GetHeight() > 0)) - { - SetSubRect(IntRect(0, 0, texture.GetWidth(), texture.GetHeight())); - } + +//////////////////////////////////////////////////////////// +void Sprite::SetTexture(const Texture& texture, bool resetRect) +{ + // Recompute the texture area if requested, or if there was no valid texture before + if (resetRect || !myTexture) + SetTextureRect(IntRect(0, 0, texture.GetWidth(), texture.GetHeight())); // Assign the new texture myTexture = &texture; @@ -76,38 +72,25 @@ void Sprite::SetTexture(const Texture& texture, bool adjustToNewSize) //////////////////////////////////////////////////////////// -void Sprite::SetSubRect(const IntRect& rectangle) +void Sprite::SetTextureRect(const IntRect& rectangle) { - mySubRect = rectangle; + if (rectangle != myTextureRect) + { + myTextureRect = rectangle; + UpdatePositions(); + UpdateTexCoords(); + } } //////////////////////////////////////////////////////////// -void Sprite::Resize(float width, float height) +void Sprite::SetColor(const Color& color) { - if ((mySubRect.Width > 0) && (mySubRect.Height > 0)) - SetScale(width / mySubRect.Width, height / mySubRect.Height); -} - - -//////////////////////////////////////////////////////////// -void Sprite::Resize(const Vector2f& size) -{ - Resize(size.x, size.y); -} - - -//////////////////////////////////////////////////////////// -void Sprite::FlipX(bool flipped) -{ - myIsFlippedX = flipped; -} - - -//////////////////////////////////////////////////////////// -void Sprite::FlipY(bool flipped) -{ - myIsFlippedY = flipped; + // Update the vertices' color + myVertices[0].Color = color; + myVertices[1].Color = color; + myVertices[2].Color = color; + myVertices[3].Color = color; } @@ -119,49 +102,73 @@ const Texture* Sprite::GetTexture() const //////////////////////////////////////////////////////////// -const IntRect& Sprite::GetSubRect() const +const IntRect& Sprite::GetTextureRect() const { - return mySubRect; + return myTextureRect; } //////////////////////////////////////////////////////////// -Vector2f Sprite::GetSize() const +const Color& Sprite::GetColor() const { - return Vector2f(mySubRect.Width * GetScale().x, mySubRect.Height * GetScale().y); + return myVertices[0].Color; } //////////////////////////////////////////////////////////// -void Sprite::Render(RenderTarget&, Renderer& renderer) const +FloatRect Sprite::GetLocalBounds() const { - // Get the sprite size - float width = static_cast(mySubRect.Width); - float height = static_cast(mySubRect.Height); + float width = static_cast(myTextureRect.Width); + float height = static_cast(myTextureRect.Height); - // Check if the texture is valid, and calculate the texture coordinates - FloatRect coords; + return FloatRect(0.f, 0.f, width, height); +} + + +//////////////////////////////////////////////////////////// +FloatRect Sprite::GetGlobalBounds() const +{ + return GetTransform().TransformRect(GetLocalBounds()); +} + + +//////////////////////////////////////////////////////////// +void Sprite::Draw(RenderTarget& target, RenderStates states) const +{ if (myTexture) - coords = myTexture->GetTexCoords(mySubRect); + { + states.Transform *= GetTransform(); + states.Texture = myTexture; + target.Draw(myVertices, 4, Quads, states); + } +} - // Compute the texture coordinates - float left = coords.Left; - float top = coords.Top; - float right = coords.Left + coords.Width; - float bottom = coords.Top + coords.Height; - if (myIsFlippedX) std::swap(left, right); - if (myIsFlippedY) std::swap(top, bottom); - // Bind the texture - renderer.SetTexture(myTexture); +//////////////////////////////////////////////////////////// +void Sprite::UpdatePositions() +{ + float width = static_cast(myTextureRect.Width); + float height = static_cast(myTextureRect.Height); - // Draw the sprite's geometry - renderer.Begin(Renderer::TriangleStrip); - renderer.AddVertex(0, 0, left, top); - renderer.AddVertex(width, 0, right, top); - renderer.AddVertex(0, height, left, bottom); - renderer.AddVertex(width, height, right, bottom); - renderer.End(); + myVertices[0].Position = Vector2f(0, 0); + myVertices[1].Position = Vector2f(0, height); + myVertices[2].Position = Vector2f(width, height); + myVertices[3].Position = Vector2f(width, 0); +} + + +//////////////////////////////////////////////////////////// +void Sprite::UpdateTexCoords() +{ + float left = static_cast(myTextureRect.Left); + float right = left + myTextureRect.Width; + float top = static_cast(myTextureRect.Top); + float bottom = top + myTextureRect.Height; + + myVertices[0].TexCoords = Vector2f(left, top); + myVertices[1].TexCoords = Vector2f(left, bottom); + myVertices[2].TexCoords = Vector2f(right, bottom); + myVertices[3].TexCoords = Vector2f(right, top); } } // namespace sf diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index bb92ec7d..a602818b 100644 --- a/src/SFML/Graphics/Text.cpp +++ b/src/SFML/Graphics/Text.cpp @@ -27,17 +27,20 @@ //////////////////////////////////////////////////////////// #include #include -#include +#include +#include namespace sf { //////////////////////////////////////////////////////////// Text::Text() : +myString (), myFont (&Font::GetDefaultFont()), myCharacterSize(30), myStyle (Regular), -myRectUpdated (true) +myVertices (Quads), +myBounds () { } @@ -45,12 +48,14 @@ myRectUpdated (true) //////////////////////////////////////////////////////////// Text::Text(const String& string, const Font& font, unsigned int characterSize) : +myString (string), myFont (&font), myCharacterSize(characterSize), myStyle (Regular), -myRectUpdated (true) +myVertices (Quads), +myBounds () { - SetString(string); + UpdateGeometry(); } @@ -58,7 +63,7 @@ myRectUpdated (true) void Text::SetString(const String& string) { myString = string; - myRectUpdated = false; + UpdateGeometry(); } @@ -68,7 +73,7 @@ void Text::SetFont(const Font& font) if (myFont != &font) { myFont = &font; - myRectUpdated = false; + UpdateGeometry(); } } @@ -79,7 +84,7 @@ void Text::SetCharacterSize(unsigned int size) if (myCharacterSize != size) { myCharacterSize = size; - myRectUpdated = false; + UpdateGeometry(); } } @@ -90,7 +95,19 @@ void Text::SetStyle(Uint32 style) if (myStyle != style) { myStyle = style; - myRectUpdated = false; + UpdateGeometry(); + } +} + + +//////////////////////////////////////////////////////////// +void Text::SetColor(const Color& color) +{ + if (color != myColor) + { + myColor = color; + for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i) + myVertices[i].Color = myColor; } } @@ -105,6 +122,7 @@ const String& Text::GetString() const //////////////////////////////////////////////////////////// const Font& Text::GetFont() const { + assert(myFont != NULL); // can never be NULL, always &Font::GetDefaultFont() by default return *myFont; } @@ -124,24 +142,29 @@ Uint32 Text::GetStyle() const //////////////////////////////////////////////////////////// -Vector2f Text::GetCharacterPos(std::size_t index) const +const Color& Text::GetColor() const { - // Make sure that we have a valid font - if (!myFont) - return Vector2f(0, 0); + return myColor; +} + + +//////////////////////////////////////////////////////////// +Vector2f Text::FindCharacterPos(std::size_t index) const +{ + assert(myFont != NULL); // Adjust the index if it's out of range if (index > myString.GetSize()) index = myString.GetSize(); - // We'll need this a lot - bool bold = (myStyle & Bold) != 0; - float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); + // Precompute the variables needed by the algorithm + bool bold = (myStyle & Bold) != 0; + float hspace = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); + float vspace = static_cast(myFont->GetLineSpacing(myCharacterSize)); // Compute the position Vector2f position; Uint32 prevChar = 0; - float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); for (std::size_t i = 0; i < index; ++i) { Uint32 curChar = myString[i]; @@ -153,69 +176,75 @@ Vector2f Text::GetCharacterPos(std::size_t index) const // Handle special characters switch (curChar) { - case L' ' : position.x += space; continue; - case L'\t' : position.x += space * 4; continue; - case L'\v' : position.y += lineSpacing * 4; continue; - case L'\n' : position.y += lineSpacing; position.x = 0; continue; + case L' ' : position.x += hspace; continue; + case L'\t' : position.x += hspace * 4; continue; + case L'\n' : position.y += vspace; position.x = 0; continue; + case L'\v' : position.y += vspace * 4; continue; } // For regular characters, add the advance offset of the glyph position.x += static_cast(myFont->GetGlyph(curChar, myCharacterSize, bold).Advance); } + // Transform the position to global coordinates + position = GetTransform().TransformPoint(position); + return position; } //////////////////////////////////////////////////////////// -FloatRect Text::GetRect() const +FloatRect Text::GetLocalBounds() const { - UpdateRect(); - - FloatRect rect; - rect.Left = (myBaseRect.Left - GetOrigin().x) * GetScale().x + GetPosition().x; - rect.Top = (myBaseRect.Top - GetOrigin().y) * GetScale().y + GetPosition().y; - rect.Width = myBaseRect.Width * GetScale().x; - rect.Height = myBaseRect.Height * GetScale().y; - - return rect; + return myBounds; } //////////////////////////////////////////////////////////// -void Text::Render(RenderTarget&, Renderer& renderer) const +FloatRect Text::GetGlobalBounds() const { - // No text or not font: nothing to render - if (!myFont || myString.IsEmpty()) + return GetTransform().TransformRect(GetLocalBounds()); +} + + +//////////////////////////////////////////////////////////// +void Text::Draw(RenderTarget& target, RenderStates states) const +{ + assert(myFont != NULL); + + states.Transform *= GetTransform(); + states.BlendMode = BlendAlpha; // alpha blending is mandatory for proper text rendering + states.Texture = &myFont->GetTexture(myCharacterSize); + target.Draw(myVertices, states); +} + + +//////////////////////////////////////////////////////////// +void Text::UpdateGeometry() +{ + assert(myFont != NULL); + + // Clear the previous geometry + myVertices.Clear(); + + // No text: nothing to draw + if (myString.IsEmpty()) return; - // Bind the font texture - const Texture& texture = myFont->GetTexture(myCharacterSize); - renderer.SetTexture(&texture); + // Compute values related to the text style + bool bold = (myStyle & Bold) != 0; + bool underlined = (myStyle & Underlined) != 0; + float italic = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees + float underlineOffset = myCharacterSize * 0.1f; + float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f); - // Computes values related to the text style - bool bold = (myStyle & Bold) != 0; - bool underlined = (myStyle & Underlined) != 0; - float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees - float underlineOffset = myCharacterSize * 0.1f; - float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f); - FloatRect underlineCoords = texture.GetTexCoords(IntRect(1, 1, 1, 1)); - float underlineLeft = underlineCoords.Left; - float underlineTop = underlineCoords.Top; - float underlineRight = underlineCoords.Left + underlineCoords.Width; - float underlineBottom = underlineCoords.Top + underlineCoords.Height; + // Precompute the variables needed by the algorithm + float hspace = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); + float vspace = static_cast(myFont->GetLineSpacing(myCharacterSize)); + float x = 0.f; + float y = static_cast(myCharacterSize); - // Initialize the rendering coordinates - float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); - float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); - float x = 0.f; - float y = static_cast(myCharacterSize); - - // Note: - // Here we use a Begin/End pair for each quad because - // the font's texture may change in a call to GetGlyph - - // Draw one quad for each character + // Create one quad for each character Uint32 prevChar = 0; for (std::size_t i = 0; i < myString.GetSize(); ++i) { @@ -231,44 +260,42 @@ void Text::Render(RenderTarget&, Renderer& renderer) const float top = y + underlineOffset; float bottom = top + underlineThickness; - renderer.Begin(Renderer::QuadList); - renderer.AddVertex(0, top, underlineLeft, underlineTop); - renderer.AddVertex(x, top, underlineRight, underlineTop); - renderer.AddVertex(x, bottom, underlineRight, underlineBottom); - renderer.AddVertex(0, bottom, underlineLeft, underlineBottom); - renderer.End(); + myVertices.Append(Vertex(Vector2f(0, top), myColor, Vector2f(1, 1))); + myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2f(2, 1))); + myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2f(2, 2))); + myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2f(1, 2))); } // Handle special characters switch (curChar) { - case L' ' : x += space; continue; - case L'\t' : x += space * 4; continue; - case L'\n' : y += lineSpacing; x = 0; continue; - case L'\v' : y += lineSpacing * 4; continue; + case L' ' : x += hspace; continue; + case L'\t' : x += hspace * 4; continue; + case L'\n' : y += vspace; x = 0; continue; + case L'\v' : y += vspace * 4; continue; } // Extract the current glyph's description - const Glyph& glyph = myFont->GetGlyph(curChar, myCharacterSize, bold); - int advance = glyph.Advance; - const IntRect& bounds = glyph.Bounds; - FloatRect coords = texture.GetTexCoords(glyph.SubRect); + const Glyph& glyph = myFont->GetGlyph(curChar, myCharacterSize, bold); - int boundsRight = bounds.Left + bounds.Width; - int boundsBottom = bounds.Top + bounds.Height; - float coordsRight = coords.Left + coords.Width; - float coordsBottom = coords.Top + coords.Height; + int left = glyph.Bounds.Left; + int top = glyph.Bounds.Top; + int right = glyph.Bounds.Left + glyph.Bounds.Width; + int bottom = glyph.Bounds.Top + glyph.Bounds.Height; - // Draw a textured quad for the current character - renderer.Begin(Renderer::QuadList); - renderer.AddVertex(x + bounds.Left - italicCoeff * bounds.Top, y + bounds.Top, coords.Left, coords.Top); - renderer.AddVertex(x + boundsRight - italicCoeff * bounds.Top, y + bounds.Top, coordsRight, coords.Top); - renderer.AddVertex(x + boundsRight - italicCoeff * boundsBottom, y + boundsBottom, coordsRight, coordsBottom); - renderer.AddVertex(x + bounds.Left - italicCoeff * boundsBottom, y + boundsBottom, coords.Left, coordsBottom); - renderer.End(); + float u1 = static_cast(glyph.TextureRect.Left); + float v1 = static_cast(glyph.TextureRect.Top); + float u2 = static_cast(glyph.TextureRect.Left + glyph.TextureRect.Width); + float v2 = static_cast(glyph.TextureRect.Top + glyph.TextureRect.Height); + + // Add a quad for the current character + myVertices.Append(Vertex(Vector2f(x + left - italic * top, y + top), myColor, Vector2f(u1, v1))); + myVertices.Append(Vertex(Vector2f(x + right - italic * top, y + top), myColor, Vector2f(u2, v1))); + myVertices.Append(Vertex(Vector2f(x + right - italic * bottom, y + bottom), myColor, Vector2f(u2, v2))); + myVertices.Append(Vertex(Vector2f(x + left - italic * bottom, y + bottom), myColor, Vector2f(u1, v2))); // Advance to the next character - x += advance; + x += glyph.Advance; } // If we're using the underlined style, add the last line @@ -277,113 +304,14 @@ void Text::Render(RenderTarget&, Renderer& renderer) const float top = y + underlineOffset; float bottom = top + underlineThickness; - renderer.Begin(Renderer::QuadList); - renderer.AddVertex(0, top, underlineLeft, underlineTop); - renderer.AddVertex(x, top, underlineRight, underlineTop); - renderer.AddVertex(x, bottom, underlineRight, underlineBottom); - renderer.AddVertex(0, bottom, underlineLeft, underlineBottom); - renderer.End(); - } -} - - -//////////////////////////////////////////////////////////// -void Text::UpdateRect() const -{ - if (myRectUpdated) - return; - - // Reset the previous states - myRectUpdated = true; - myBaseRect = FloatRect(0, 0, 0, 0); - - // No text or not font: empty box - if (!myFont || myString.IsEmpty()) - return; - - // Initial values - bool bold = (myStyle & Bold) != 0; - float charSize = static_cast(myCharacterSize); - float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance); - float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); - float curWidth = 0; - float curHeight = 0; - float width = 0; - float height = 0; - Uint32 prevChar = 0; - - // Go through each character - for (std::size_t i = 0; i < myString.GetSize(); ++i) - { - Uint32 curChar = myString[i]; - - // Apply the kerning offset - curWidth += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize)); - prevChar = curChar; - - // Handle special characters - switch (curChar) - { - case L' ' : - curWidth += space; - continue; - - case L'\t' : - curWidth += space * 4; - continue; - - case L'\v' : - height += lineSpacing * 4; - curHeight = 0; - continue; - - case L'\n' : - height += lineSpacing; - curHeight = 0; - if (curWidth > width) - width = curWidth; - curWidth = 0; - continue; - } - - // Extract the current glyph's description - const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize, bold); - - // Advance to the next character - curWidth += static_cast(curGlyph.Advance); - - // Update the maximum height - float charHeight = charSize + curGlyph.Bounds.Top + curGlyph.Bounds.Height; - if (charHeight > curHeight) - curHeight = charHeight; + myVertices.Append(Vertex(Vector2f(0, top), myColor, Vector2f(1, 1))); + myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2f(2, 1))); + myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2f(2, 2))); + myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2f(1, 2))); } - // Update the last line - if (curWidth > width) - width = curWidth; - height += curHeight; - - // Add a slight width if we're using the italic style - if (myStyle & Italic) - { - width += 0.208f * charSize; - } - - // Add a slight height if we're using the underlined style - if (myStyle & Underlined) - { - float underlineOffset = myCharacterSize * 0.1f; - float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f); - - if (curHeight < charSize + underlineOffset + underlineThickness) - height += underlineOffset + underlineThickness; - } - - // Finally update the rectangle - myBaseRect.Left = 0; - myBaseRect.Top = 0; - myBaseRect.Width = width; - myBaseRect.Height = height; + // Recompute the bounding rectangle + myBounds = myVertices.GetBounds(); } } // namespace sf diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp index 0517927f..22207fe7 100644 --- a/src/SFML/Graphics/Texture.cpp +++ b/src/SFML/Graphics/Texture.cpp @@ -28,12 +28,33 @@ #include #include #include +#include #include +#include +#include #include #include #include +//////////////////////////////////////////////////////////// +// Private data +//////////////////////////////////////////////////////////// +namespace +{ + // Thread-safe unique identifier generator, + // is used for states cache (see RenderTarget) + sf::Uint64 GetUniqueId() + { + static sf::Uint64 id = 1; // start at 1, zero is "no texture" + static sf::Mutex mutex; + + sf::Lock lock(mutex); + return id++; + } +} + + namespace sf { //////////////////////////////////////////////////////////// @@ -44,7 +65,9 @@ myTextureWidth (0), myTextureHeight(0), myTexture (0), myIsSmooth (false), -myPixelsFlipped(false) +myIsRepeated (false), +myPixelsFlipped(false), +myCacheId (GetUniqueId()) { } @@ -58,7 +81,9 @@ myTextureWidth (0), myTextureHeight(0), myTexture (0), myIsSmooth (copy.myIsSmooth), -myPixelsFlipped(false) +myIsRepeated (copy.myIsRepeated), +myPixelsFlipped(false), +myCacheId (GetUniqueId()) { if (copy.myTexture) LoadFromImage(copy.CopyToImage()); @@ -121,13 +146,17 @@ bool Texture::Create(unsigned int width, unsigned int height) myTexture = static_cast(texture); } + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Initialize the texture GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)); - GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE)); + GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE)); GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST)); GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST)); + myCacheId = GetUniqueId(); return true; } @@ -193,6 +222,9 @@ bool Texture::LoadFromImage(const Image& image, const IntRect& area) // Create the texture and upload the pixels if (Create(rectangle.Width, rectangle.Height)) { + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Copy the pixels to the texture, row by row const Uint8* pixels = image.GetPixelsPtr() + 4 * (rectangle.Left + (width * rectangle.Top)); GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); @@ -235,6 +267,9 @@ Image Texture::CopyToImage() const EnsureGlContext(); + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Create an array of pixels std::vector pixels(myWidth * myHeight * 4); @@ -300,10 +335,14 @@ void Texture::Update(const Uint8* pixels, unsigned int width, unsigned int heigh { EnsureGlContext(); + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Copy pixels from the given array to the texture GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); myPixelsFlipped = false; + myCacheId = GetUniqueId(); } } @@ -338,18 +377,54 @@ void Texture::Update(const Window& window, unsigned int x, unsigned int y) if (myTexture && window.SetActive(true)) { + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + // Copy pixels from the back-buffer to the texture GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.GetWidth(), window.GetHeight())); myPixelsFlipped = true; + myCacheId = GetUniqueId(); } } //////////////////////////////////////////////////////////// -void Texture::Bind() const +void Texture::Bind(CoordinateType coordinateType) const { + // Bind the texture GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); + + // Check if we need to define a special texture matrix + if ((coordinateType == Pixels) || myPixelsFlipped) + { + GLfloat matrix[16] = {1.f, 0.f, 0.f, 0.f, + 0.f, 1.f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f}; + + // If non-normalized coordinates (= pixels) are requested, we need to + // setup scale factors that convert the range [0 .. size] to [0 .. 1] + if (coordinateType == Pixels) + { + matrix[0] = 1.f / myTextureWidth; + matrix[5] = 1.f / myTextureHeight; + } + + // If pixels are flipped we must invert the Y axis + if (myPixelsFlipped) + { + matrix[5] = -matrix[5]; + matrix[13] = static_cast(myHeight / myTextureHeight); + } + + // Load the matrix + GLCheck(glMatrixMode(GL_TEXTURE)); + GLCheck(glLoadMatrixf(matrix)); + + // Go back to model-view mode (sf::RenderTarget relies on it) + GLCheck(glMatrixMode(GL_MODELVIEW)); + } } @@ -364,6 +439,9 @@ void Texture::SetSmooth(bool smooth) { EnsureGlContext(); + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST)); GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST)); @@ -380,32 +458,31 @@ bool Texture::IsSmooth() const //////////////////////////////////////////////////////////// -FloatRect Texture::GetTexCoords(const IntRect& rect) const +void Texture::SetRepeated(bool repeated) { - if ((myTextureWidth != 0) && (myTextureHeight != 0)) + if (repeated != myIsRepeated) { - float width = static_cast(myTextureWidth); - float height = static_cast(myTextureHeight); + myIsRepeated = repeated; - if (myPixelsFlipped) + if (myTexture) { - return FloatRect( rect.Left / width, - (myHeight - rect.Top) / height, - rect.Width / width, - -rect.Height / height); - } - else - { - return FloatRect(rect.Left / width, - rect.Top / height, - rect.Width / width, - rect.Height / height); + EnsureGlContext(); + + // Make sure that the current texture binding will be preserved + priv::TextureSaver save; + + GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture)); + GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE)); + GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE)); } } - else - { - return FloatRect(0, 0, 0, 0); - } +} + + +//////////////////////////////////////////////////////////// +bool Texture::IsRepeated() const +{ + return myIsRepeated; } @@ -432,7 +509,9 @@ Texture& Texture::operator =(const Texture& right) std::swap(myTextureHeight, temp.myTextureHeight); std::swap(myTexture, temp.myTexture); std::swap(myIsSmooth, temp.myIsSmooth); + std::swap(myIsRepeated, temp.myIsRepeated); std::swap(myPixelsFlipped, temp.myPixelsFlipped); + myCacheId = GetUniqueId(); return *this; } diff --git a/src/SFML/Graphics/Matrix3.cpp b/src/SFML/Graphics/TextureSaver.cpp similarity index 83% rename from src/SFML/Graphics/Matrix3.cpp rename to src/SFML/Graphics/TextureSaver.cpp index 7de4b0f6..e4bbecd3 100644 --- a/src/SFML/Graphics/Matrix3.cpp +++ b/src/SFML/Graphics/TextureSaver.cpp @@ -1,40 +1,50 @@ -//////////////////////////////////////////////////////////// -// -// SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) -// -// This software is provided 'as-is', without any express or implied warranty. -// In no event will the authors be held liable for any damages arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it freely, -// subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; -// you must not claim that you wrote the original software. -// If you use this software in a product, an acknowledgment -// in the product documentation would be appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, -// and must not be misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// Headers -//////////////////////////////////////////////////////////// -#include - - -namespace sf -{ -//////////////////////////////////////////////////////////// -// Static member data -//////////////////////////////////////////////////////////// -const Matrix3 Matrix3::Identity(1, 0, 0, - 0, 1, 0, - 0, 0, 1); - -} // namespace sf +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +TextureSaver::TextureSaver() +{ + GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &myTextureBinding)); +} + + +//////////////////////////////////////////////////////////// +TextureSaver::~TextureSaver() +{ + GLCheck(glBindTexture(GL_TEXTURE_2D, myTextureBinding)); +} + +} // namespace priv + +} // namespace sf diff --git a/src/SFML/Graphics/TextureSaver.hpp b/src/SFML/Graphics/TextureSaver.hpp new file mode 100644 index 00000000..845cffb7 --- /dev/null +++ b/src/SFML/Graphics/TextureSaver.hpp @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_TEXTURESAVER_HPP +#define SFML_TEXTURESAVER_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief Automatic wrapper for saving and restoring the current texture binding +/// +//////////////////////////////////////////////////////////// +class TextureSaver +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// The current texture binding is saved. + /// + //////////////////////////////////////////////////////////// + TextureSaver(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// The previous texture binding is restored. + /// + //////////////////////////////////////////////////////////// + ~TextureSaver(); + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + GLint myTextureBinding; ///< Texture binding to restore +}; + +} // namespace priv + +} // namespace sf + + +#endif // SFML_TEXTURESAVER_HPP diff --git a/src/SFML/Graphics/Transform.cpp b/src/SFML/Graphics/Transform.cpp new file mode 100644 index 00000000..3d459ca6 --- /dev/null +++ b/src/SFML/Graphics/Transform.cpp @@ -0,0 +1,270 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +const Transform Transform::Identity; + + +//////////////////////////////////////////////////////////// +Transform::Transform() +{ + // Identity matrix + myMatrix[0] = 1.f; myMatrix[4] = 0.f; myMatrix[8] = 0.f; myMatrix[12] = 0.f; + myMatrix[1] = 0.f; myMatrix[5] = 1.f; myMatrix[9] = 0.f; myMatrix[13] = 0.f; + myMatrix[2] = 0.f; myMatrix[6] = 0.f; myMatrix[10] = 1.f; myMatrix[14] = 0.f; + myMatrix[3] = 0.f; myMatrix[7] = 0.f; myMatrix[11] = 0.f; myMatrix[15] = 1.f; +} + + +//////////////////////////////////////////////////////////// +Transform::Transform(float a00, float a01, float a02, + float a10, float a11, float a12, + float a20, float a21, float a22) +{ + myMatrix[0] = a00; myMatrix[4] = a01; myMatrix[8] = 0.f; myMatrix[12] = a02; + myMatrix[1] = a10; myMatrix[5] = a11; myMatrix[9] = 0.f; myMatrix[13] = a12; + myMatrix[2] = 0.f; myMatrix[6] = 0.f; myMatrix[10] = 1.f; myMatrix[14] = 0.f; + myMatrix[3] = a20; myMatrix[7] = a21; myMatrix[11] = 0.f; myMatrix[15] = a22; +} + + +//////////////////////////////////////////////////////////// +const float* Transform::GetMatrix() const +{ + return myMatrix; +} + + +//////////////////////////////////////////////////////////// +Transform Transform::GetInverse() const +{ + // Compute the determinant + float det = myMatrix[0] * (myMatrix[15] * myMatrix[5] - myMatrix[7] * myMatrix[13]) - + myMatrix[1] * (myMatrix[15] * myMatrix[4] - myMatrix[7] * myMatrix[12]) + + myMatrix[3] * (myMatrix[13] * myMatrix[4] - myMatrix[5] * myMatrix[12]); + + // Compute the inverse if the determinant is not zero + // (don't use an epsilon because the determinant may *really* be tiny) + if (det != 0.f) + { + return Transform( (myMatrix[15] * myMatrix[5] - myMatrix[7] * myMatrix[13]) / det, + -(myMatrix[15] * myMatrix[4] - myMatrix[7] * myMatrix[12]) / det, + (myMatrix[13] * myMatrix[4] - myMatrix[5] * myMatrix[12]) / det, + -(myMatrix[15] * myMatrix[1] - myMatrix[3] * myMatrix[13]) / det, + (myMatrix[15] * myMatrix[0] - myMatrix[3] * myMatrix[12]) / det, + -(myMatrix[13] * myMatrix[0] - myMatrix[1] * myMatrix[12]) / det, + (myMatrix[7] * myMatrix[1] - myMatrix[3] * myMatrix[5]) / det, + -(myMatrix[7] * myMatrix[0] - myMatrix[3] * myMatrix[4]) / det, + (myMatrix[5] * myMatrix[0] - myMatrix[1] * myMatrix[4]) / det); + } + else + { + return Identity; + } +} + + +//////////////////////////////////////////////////////////// +Vector2f Transform::TransformPoint(float x, float y) const +{ + return Vector2f(myMatrix[0] * x + myMatrix[4] * y + myMatrix[12], + myMatrix[1] * x + myMatrix[5] * y + myMatrix[13]); +} + + +//////////////////////////////////////////////////////////// +Vector2f Transform::TransformPoint(const Vector2f& point) const +{ + return TransformPoint(point.x, point.y); +} + + +//////////////////////////////////////////////////////////// +FloatRect Transform::TransformRect(const FloatRect& rectangle) const +{ + // Transform the 4 corners of the rectangle + const Vector2f points[] = + { + TransformPoint(rectangle.Left, rectangle.Top), + TransformPoint(rectangle.Left, rectangle.Top + rectangle.Height), + TransformPoint(rectangle.Left + rectangle.Width, rectangle.Top), + TransformPoint(rectangle.Left + rectangle.Width, rectangle.Top + rectangle.Height) + }; + + // Compute the bounding rectangle of the transformed points + float left = points[0].x; + float top = points[0].y; + float right = points[0].x; + float bottom = points[0].y; + for (int i = 1; i < 4; ++i) + { + if (points[i].x < left) left = points[i].x; + else if (points[i].x > right) right = points[i].x; + if (points[i].y < top) top = points[i].y; + else if (points[i].y > bottom) bottom = points[i].y; + } + + return FloatRect(left, top, right - left, bottom - top); +} + + +//////////////////////////////////////////////////////////// +Transform Transform::Combine(const Transform& transform) const +{ + const float* a = myMatrix; + const float* b = transform.myMatrix; + + return Transform(a[0] * b[0] + a[4] * b[1] + a[12] * b[3], + a[0] * b[4] + a[4] * b[5] + a[12] * b[7], + a[0] * b[12] + a[4] * b[13] + a[12] * b[15], + a[1] * b[0] + a[5] * b[1] + a[13] * b[3], + a[1] * b[4] + a[5] * b[5] + a[13] * b[7], + a[1] * b[12] + a[5] * b[13] + a[13] * b[15], + a[3] * b[0] + a[7] * b[1] + a[15] * b[3], + a[3] * b[4] + a[7] * b[5] + a[15] * b[7], + a[3] * b[12] + a[7] * b[13] + a[15] * b[15]); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Translate(float x, float y) +{ + Transform translation(1, 0, x, + 0, 1, y, + 0, 0, 1); + + return *this = Combine(translation); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Translate(const Vector2f& offset) +{ + return Translate(offset.x, offset.y); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Rotate(float angle) +{ + float rad = angle * 3.141592654f / 180.f; + float cos = std::cos(rad); + float sin = std::sin(rad); + + Transform rotation(cos, -sin, 0, + sin, cos, 0, + 0, 0, 1); + + return *this = Combine(rotation); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Rotate(float angle, float centerX, float centerY) +{ + float rad = angle * 3.141592654f / 180.f; + float cos = std::cos(rad); + float sin = std::sin(rad); + + Transform rotation(cos, -sin, centerX * (1 - cos) + centerY * sin, + sin, cos, centerY * (1 - cos) - centerX * sin, + 0, 0, 1); + + return *this = Combine(rotation); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Rotate(float angle, const Vector2f& center) +{ + return Rotate(angle, center.x, center.y); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Scale(float scaleX, float scaleY) +{ + Transform scaling(scaleX, 0, 0, + 0, scaleY, 0, + 0, 0, 1); + + return *this = Combine(scaling); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Scale(float scaleX, float scaleY, float centerX, float centerY) +{ + Transform scaling(scaleX, 0, centerX * (1 - scaleX), + 0, scaleY, centerY * (1 - scaleY), + 0, 0, 1); + + return *this = Combine(scaling); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Scale(const Vector2f& factors) +{ + return Scale(factors.x, factors.y); +} + + +//////////////////////////////////////////////////////////// +Transform& Transform::Scale(const Vector2f& factors, const Vector2f& center) +{ + return Scale(factors.x, factors.y, center.x, center.y); +} + + +//////////////////////////////////////////////////////////// +Transform operator *(const Transform& left, const Transform& right) +{ + return left.Combine(right); +} + + +//////////////////////////////////////////////////////////// +Transform& operator *=(Transform& left, const Transform& right) +{ + return left = left.Combine(right); +} + + +//////////////////////////////////////////////////////////// +Vector2f operator *(const Transform& left, const Vector2f& right) +{ + return left.TransformPoint(right); +} + +} // namespace sf diff --git a/src/SFML/Graphics/Transformable.cpp b/src/SFML/Graphics/Transformable.cpp new file mode 100644 index 00000000..004a22b5 --- /dev/null +++ b/src/SFML/Graphics/Transformable.cpp @@ -0,0 +1,216 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +Transformable::Transformable() : +myOrigin (0, 0), +myPosition (0, 0), +myRotation (0), +myScale (1, 1), +myTransform (), +myTransformNeedUpdate (true), +myInverseTransform (), +myInverseTransformNeedUpdate(true) +{ +} + + +//////////////////////////////////////////////////////////// +Transformable::~Transformable() +{ +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetPosition(float x, float y) +{ + myPosition.x = x; + myPosition.y = y; + myTransformNeedUpdate = true; + myInverseTransformNeedUpdate = true; +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetPosition(const Vector2f& position) +{ + SetPosition(position.x, position.y); +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetRotation(float angle) +{ + myRotation = angle; + myTransformNeedUpdate = true; + myInverseTransformNeedUpdate = true; +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetScale(float factorX, float factorY) +{ + myScale.x = factorX; + myScale.y = factorY; + myTransformNeedUpdate = true; + myInverseTransformNeedUpdate = true; +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetScale(const Vector2f& factors) +{ + SetScale(factors.x, factors.y); +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetOrigin(float x, float y) +{ + myOrigin.x = x; + myOrigin.y = y; + myTransformNeedUpdate = true; + myInverseTransformNeedUpdate = true; +} + + +//////////////////////////////////////////////////////////// +void Transformable::SetOrigin(const Vector2f& origin) +{ + SetOrigin(origin.x, origin.y); +} + + +//////////////////////////////////////////////////////////// +const Vector2f& Transformable::GetPosition() const +{ + return myPosition; +} + + +//////////////////////////////////////////////////////////// +float Transformable::GetRotation() const +{ + return myRotation; +} + + +//////////////////////////////////////////////////////////// +const Vector2f& Transformable::GetScale() const +{ + return myScale; +} + + +//////////////////////////////////////////////////////////// +const Vector2f& Transformable::GetOrigin() const +{ + return myOrigin; +} + + +//////////////////////////////////////////////////////////// +void Transformable::Move(float offsetX, float offsetY) +{ + SetPosition(myPosition.x + offsetX, myPosition.y + offsetY); +} + + +//////////////////////////////////////////////////////////// +void Transformable::Move(const Vector2f& offset) +{ + SetPosition(myPosition.x + offset.x, myPosition.y + offset.y); +} + + +//////////////////////////////////////////////////////////// +void Transformable::Rotate(float angle) +{ + SetRotation(myRotation + angle); +} + + +//////////////////////////////////////////////////////////// +void Transformable::Scale(float factorX, float factorY) +{ + SetScale(myScale.x * factorX, myScale.y * factorY); +} + + +//////////////////////////////////////////////////////////// +void Transformable::Scale(const Vector2f& factor) +{ + SetScale(myScale.x * factor.x, myScale.y * factor.y); +} + + +//////////////////////////////////////////////////////////// +const Transform& Transformable::GetTransform() const +{ + // Recompute the combined transform if needed + if (myTransformNeedUpdate) + { + float angle = -myRotation * 3.141592654f / 180.f; + float cosine = static_cast(std::cos(angle)); + float sine = static_cast(std::sin(angle)); + float sxc = myScale.x * cosine; + float syc = myScale.y * cosine; + float sxs = myScale.x * sine; + float sys = myScale.y * sine; + float tx = -myOrigin.x * sxc - myOrigin.y * sys + myPosition.x; + float ty = myOrigin.x * sxs - myOrigin.y * syc + myPosition.y; + + myTransform = Transform( sxc, sys, tx, + -sxs, syc, ty, + 0.f, 0.f, 1.f); + myTransformNeedUpdate = false; + } + + return myTransform; +} + + +//////////////////////////////////////////////////////////// +const Transform& Transformable::GetInverseTransform() const +{ + // Recompute the inverse transform if needed + if (myInverseTransformNeedUpdate) + { + myInverseTransform = GetTransform().GetInverse(); + myInverseTransformNeedUpdate = false; + } + + return myInverseTransform; +} + +} // namespace sf diff --git a/src/SFML/Graphics/Vertex.cpp b/src/SFML/Graphics/Vertex.cpp new file mode 100644 index 00000000..abdbedcd --- /dev/null +++ b/src/SFML/Graphics/Vertex.cpp @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +Vertex::Vertex() : +Position (0, 0), +Color (255, 255, 255), +TexCoords(0, 0) +{ +} + + +//////////////////////////////////////////////////////////// +Vertex::Vertex(const Vector2f& position) : +Position (position), +Color (255, 255, 255), +TexCoords(0, 0) +{ +} + + +//////////////////////////////////////////////////////////// +Vertex::Vertex(const Vector2f& position, const sf::Color& color) : +Position (position), +Color (color), +TexCoords(0, 0) +{ +} + + +//////////////////////////////////////////////////////////// +Vertex::Vertex(const Vector2f& position, const Vector2f& texCoords) : +Position (position), +Color (255, 255, 255), +TexCoords(texCoords) +{ +} + + +//////////////////////////////////////////////////////////// +Vertex::Vertex(const Vector2f& position, const sf::Color& color, const Vector2f& texCoords) : +Position (position), +Color (color), +TexCoords(texCoords) +{ +} + +} // namespace sf diff --git a/src/SFML/Graphics/VertexArray.cpp b/src/SFML/Graphics/VertexArray.cpp new file mode 100644 index 00000000..eeb1d230 --- /dev/null +++ b/src/SFML/Graphics/VertexArray.cpp @@ -0,0 +1,150 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +VertexArray::VertexArray() : +myVertices (), +myPrimitiveType(Points) +{ +} + + +//////////////////////////////////////////////////////////// +VertexArray::VertexArray(PrimitiveType type, unsigned int verticesCount) : +myVertices (verticesCount), +myPrimitiveType(type) +{ +} + + +//////////////////////////////////////////////////////////// +unsigned int VertexArray::GetVerticesCount() const +{ + return myVertices.size(); +} + + +//////////////////////////////////////////////////////////// +Vertex& VertexArray::operator [](unsigned int index) +{ + return myVertices[index]; +} + + +//////////////////////////////////////////////////////////// +const Vertex& VertexArray::operator [](unsigned int index) const +{ + return myVertices[index]; +} + + +//////////////////////////////////////////////////////////// +void VertexArray::Clear() +{ + myVertices.clear(); +} + + +//////////////////////////////////////////////////////////// +void VertexArray::Resize(unsigned int verticesCount) +{ + myVertices.resize(verticesCount); +} + + +//////////////////////////////////////////////////////////// +void VertexArray::Append(const Vertex& vertex) +{ + myVertices.push_back(vertex); +} + + +//////////////////////////////////////////////////////////// +void VertexArray::SetPrimitiveType(PrimitiveType type) +{ + myPrimitiveType = type; +} + + +//////////////////////////////////////////////////////////// +PrimitiveType VertexArray::GetPrimitiveType() const +{ + return myPrimitiveType; +} + + +//////////////////////////////////////////////////////////// +FloatRect VertexArray::GetBounds() const +{ + if (!myVertices.empty()) + { + float left = myVertices[0].Position.x; + float top = myVertices[0].Position.y; + float right = myVertices[0].Position.x; + float bottom = myVertices[0].Position.y; + + for (std::size_t i = 0; i < myVertices.size(); ++i) + { + Vector2f position = myVertices[i].Position; + + // Update left and right + if (position.x < left) + left = position.x; + else if (position.x > right) + right = position.x; + + // Update top and bottom + if (position.y < top) + top = position.y; + else if (position.y > bottom) + bottom = position.y; + } + + return FloatRect(left, top, right - left, bottom - top); + } + else + { + // Array is empty + return FloatRect(); + } +} + + +//////////////////////////////////////////////////////////// +void VertexArray::Draw(RenderTarget& target, RenderStates states) const +{ + if (!myVertices.empty()) + target.Draw(&myVertices[0], myVertices.size(), myPrimitiveType, states); +} + +} // namespace sf diff --git a/src/SFML/Graphics/View.cpp b/src/SFML/Graphics/View.cpp index 7c012ed8..ec95ddba 100644 --- a/src/SFML/Graphics/View.cpp +++ b/src/SFML/Graphics/View.cpp @@ -26,18 +26,19 @@ // Headers //////////////////////////////////////////////////////////// #include +#include namespace sf { //////////////////////////////////////////////////////////// View::View() : -myCenter (), -mySize (), -myRotation (0), -myViewport (0, 0, 1, 1), -myMatrixUpdated (false), -myInvMatrixUpdated(false) +myCenter (), +mySize (), +myRotation (0), +myViewport (0, 0, 1, 1), +myTransformUpdated (false), +myInvTransformUpdated(false) { Reset(FloatRect(0, 0, 1000, 1000)); } @@ -45,12 +46,12 @@ myInvMatrixUpdated(false) //////////////////////////////////////////////////////////// View::View(const FloatRect& rectangle) : -myCenter (), -mySize (), -myRotation (0), -myViewport (0, 0, 1, 1), -myMatrixUpdated (false), -myInvMatrixUpdated(false) +myCenter (), +mySize (), +myRotation (0), +myViewport (0, 0, 1, 1), +myTransformUpdated (false), +myInvTransformUpdated(false) { Reset(rectangle); } @@ -58,12 +59,12 @@ myInvMatrixUpdated(false) //////////////////////////////////////////////////////////// View::View(const Vector2f& center, const Vector2f& size) : -myCenter (center), -mySize (size), -myRotation (0), -myViewport (0, 0, 1, 1), -myMatrixUpdated (false), -myInvMatrixUpdated(false) +myCenter (center), +mySize (size), +myRotation (0), +myViewport (0, 0, 1, 1), +myTransformUpdated (false), +myInvTransformUpdated(false) { } @@ -74,8 +75,8 @@ void View::SetCenter(float x, float y) myCenter.x = x; myCenter.y = y; - myMatrixUpdated = false; - myInvMatrixUpdated = false; + myTransformUpdated = false; + myInvTransformUpdated = false; } @@ -92,8 +93,8 @@ void View::SetSize(float width, float height) mySize.x = width; mySize.y = height; - myMatrixUpdated = false; - myInvMatrixUpdated = false; + myTransformUpdated = false; + myInvTransformUpdated = false; } @@ -111,8 +112,8 @@ void View::SetRotation(float angle) if (myRotation < 0) myRotation += 360.f; - myMatrixUpdated = false; - myInvMatrixUpdated = false; + myTransformUpdated = false; + myInvTransformUpdated = false; } @@ -132,8 +133,8 @@ void View::Reset(const FloatRect& rectangle) mySize.y = rectangle.Height; myRotation = 0; - myMatrixUpdated = false; - myInvMatrixUpdated = false; + myTransformUpdated = false; + myInvTransformUpdated = false; } @@ -194,30 +195,46 @@ void View::Zoom(float factor) //////////////////////////////////////////////////////////// -const Matrix3& View::GetMatrix() const +const Transform& View::GetTransform() const { // Recompute the matrix if needed - if (!myMatrixUpdated) + if (!myTransformUpdated) { - myMatrix = Matrix3::Projection(myCenter, mySize, myRotation); - myMatrixUpdated = true; + // Rotation components + float angle = myRotation * 3.141592654f / 180.f; + float cosine = static_cast(std::cos(angle)); + float sine = static_cast(std::sin(angle)); + float tx = -myCenter.x * cosine - myCenter.y * sine + myCenter.x; + float ty = myCenter.x * sine - myCenter.y * cosine + myCenter.y; + + // Projection components + float a = 2.f / mySize.x; + float b = -2.f / mySize.y; + float c = -a * myCenter.x; + float d = -b * myCenter.y; + + // Rebuild the projection matrix + myTransform = Transform( a * cosine, a * sine, a * tx + c, + -b * sine, b * cosine, b * ty + d, + 0.f, 0.f, 1.f); + myTransformUpdated = true; } - return myMatrix; + return myTransform; } //////////////////////////////////////////////////////////// -const Matrix3& View::GetInverseMatrix() const +const Transform& View::GetInverseTransform() const { // Recompute the matrix if needed - if (!myInvMatrixUpdated) + if (!myInvTransformUpdated) { - myInverseMatrix = GetMatrix().GetInverse(); - myInvMatrixUpdated = true; + myInverseTransform = GetTransform().GetInverse(); + myInvTransformUpdated = true; } - return myInverseMatrix; + return myInverseTransform; } } // namespace sf