From 5bae08a2d8d0dba34268150d96071a4546ab49c5 Mon Sep 17 00:00:00 2001 From: Laurent Gomila Date: Thu, 1 Dec 2011 23:24:58 +0100 Subject: [PATCH] Implemented the new graphics API: - Removed the internal classes sf::Renderer and sf::Matrix3 - Split sf::Drawable into sf::Drawable and sf::Transformable - Added sf::Transform - Added sf::Vertex - Added sf::VertexArray - Types of shapes are now handled with their own derived class - Modified the Pong example --- examples/opengl/OpenGL.cpp | 11 +- examples/pong/Pong.cpp | 218 ++++--- examples/pong/resources/background.jpg | Bin 90083 -> 0 bytes examples/pong/resources/ball.png | Bin 249 -> 0 bytes examples/pong/resources/paddle_left.png | Bin 762 -> 0 bytes examples/pong/resources/paddle_right.png | Bin 683 -> 0 bytes examples/shader/Shader.cpp | 10 +- examples/sound/Sound.cpp | 6 +- examples/sound_capture/SoundCapture.cpp | 3 +- examples/win32/Win32.cpp | 10 +- include/SFML/Graphics.hpp | 10 +- .../SFML/Graphics/BlendMode.hpp | 86 +-- include/SFML/Graphics/CircleShape.hpp | 129 ++++ include/SFML/Graphics/Color.hpp | 42 +- include/SFML/Graphics/ConvexShape.hpp | 164 ++++++ include/SFML/Graphics/Drawable.hpp | 528 +---------------- include/SFML/Graphics/Glyph.hpp | 8 +- include/SFML/Graphics/Matrix3.hpp | 176 ------ include/SFML/Graphics/Matrix3.inl | 147 ----- include/SFML/Graphics/PrimitiveType.hpp | 53 ++ include/SFML/Graphics/Rect.hpp | 30 + include/SFML/Graphics/Rect.inl | 18 + include/SFML/Graphics/RectangleShape.hpp | 129 ++++ include/SFML/Graphics/RenderStates.hpp | 173 ++++++ include/SFML/Graphics/RenderTarget.hpp | 168 +++--- include/SFML/Graphics/RenderWindow.hpp | 29 +- include/SFML/Graphics/Renderer.hpp | 363 ------------ include/SFML/Graphics/Shader.hpp | 17 +- include/SFML/Graphics/Shape.hpp | 555 ++++++------------ include/SFML/Graphics/Sprite.hpp | 204 ++++--- include/SFML/Graphics/StarShape.hpp | 178 ++++++ include/SFML/Graphics/Text.hpp | 119 ++-- include/SFML/Graphics/Texture.hpp | 64 +- include/SFML/Graphics/Transform.hpp | 450 ++++++++++++++ include/SFML/Graphics/Transformable.hpp | 414 +++++++++++++ include/SFML/Graphics/Vertex.hpp | 143 +++++ include/SFML/Graphics/VertexArray.hpp | 220 +++++++ include/SFML/Graphics/View.hpp | 38 +- include/SFML/System/Utf.hpp | 3 - include/SFML/System/Vector3.hpp | 2 +- include/SFML/Window/Context.hpp | 14 + src/SFML/Graphics/CMakeLists.txt | 26 +- src/SFML/Graphics/CircleShape.cpp | 73 +++ src/SFML/Graphics/Color.cpp | 1 + src/SFML/Graphics/ConvexShape.cpp | 85 +++ src/SFML/Graphics/Drawable.cpp | 314 ---------- src/SFML/Graphics/Font.cpp | 10 +- src/SFML/Graphics/RectangleShape.cpp | 76 +++ src/SFML/Graphics/RenderStates.cpp | 98 ++++ src/SFML/Graphics/RenderTarget.cpp | 241 +++++--- src/SFML/Graphics/Renderer.cpp | 348 ----------- src/SFML/Graphics/Shader.cpp | 2 +- src/SFML/Graphics/Shape.cpp | 414 +++++-------- src/SFML/Graphics/Sprite.cpp | 155 ++--- src/SFML/Graphics/StarShape.cpp | 107 ++++ src/SFML/Graphics/Text.cpp | 306 ++++------ src/SFML/Graphics/Texture.cpp | 74 ++- src/SFML/Graphics/Transform.cpp | 270 +++++++++ src/SFML/Graphics/Transformable.cpp | 210 +++++++ src/SFML/Graphics/Vertex.cpp | 77 +++ src/SFML/Graphics/VertexArray.cpp | 150 +++++ src/SFML/Graphics/View.cpp | 89 +-- src/SFML/Window/Context.cpp | 7 + src/SFML/Window/GlContext.cpp | 7 + src/SFML/Window/GlContext.hpp | 10 + 65 files changed, 4756 insertions(+), 3326 deletions(-) delete mode 100644 examples/pong/resources/background.jpg delete mode 100644 examples/pong/resources/ball.png delete mode 100644 examples/pong/resources/paddle_left.png delete mode 100644 examples/pong/resources/paddle_right.png rename src/SFML/Graphics/Matrix3.cpp => include/SFML/Graphics/BlendMode.hpp (76%) create mode 100644 include/SFML/Graphics/CircleShape.hpp create mode 100644 include/SFML/Graphics/ConvexShape.hpp delete mode 100644 include/SFML/Graphics/Matrix3.hpp delete mode 100644 include/SFML/Graphics/Matrix3.inl create mode 100644 include/SFML/Graphics/PrimitiveType.hpp create mode 100644 include/SFML/Graphics/RectangleShape.hpp create mode 100644 include/SFML/Graphics/RenderStates.hpp delete mode 100644 include/SFML/Graphics/Renderer.hpp create mode 100644 include/SFML/Graphics/StarShape.hpp create mode 100644 include/SFML/Graphics/Transform.hpp create mode 100644 include/SFML/Graphics/Transformable.hpp create mode 100644 include/SFML/Graphics/Vertex.hpp create mode 100644 include/SFML/Graphics/VertexArray.hpp create mode 100644 src/SFML/Graphics/CircleShape.cpp create mode 100644 src/SFML/Graphics/ConvexShape.cpp delete mode 100644 src/SFML/Graphics/Drawable.cpp create mode 100644 src/SFML/Graphics/RectangleShape.cpp create mode 100644 src/SFML/Graphics/RenderStates.cpp delete mode 100644 src/SFML/Graphics/Renderer.cpp create mode 100644 src/SFML/Graphics/StarShape.cpp create mode 100644 src/SFML/Graphics/Transform.cpp create mode 100644 src/SFML/Graphics/Transformable.cpp create mode 100644 src/SFML/Graphics/Vertex.cpp create mode 100644 src/SFML/Graphics/VertexArray.cpp 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 06dfdb8b896d61f514afae267c2efff92e67906c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90083 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%0ADe#?&Gk2Sa$`BL+_J+QJ?6~`I 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໬_o{{SlAw^N*|UNLQ0 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%0Avai`sdIF2)q5baj| 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 M?N_VSGSrj*+1th1p8x;= diff --git a/examples/pong/resources/ball.png b/examples/pong/resources/ball.png deleted file mode 100644 index c296859b6bc4de85878d2fa3a840e767acc2543a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%>?NMQuI$%2goNa@^DaD21`2T& zctjR6FmQbUVMeDlCNqG7Gdx`!Ln?0FopzD;fC7gLcl3_`c~))5`pvGbYG9r9W#4)0 z`HC(lEahXCPRV;Fz*KOaDfCMFd6%h++&GV0t4tCpcq!+S@0}*;A-UyLfw{-3)gF`6 zro8k{al9P7Q_!*JV$ZUv|F8UA?y>1rd8l>G{Bx6Do%tru#=Xky^X!k;mb}_L!6;)& uh;F^(rM3HZsl1b$QgyQaZdX9jL?%8K|4i1Ef*n9NGI+ZBxvX!A z|33cyDNAI0g z%**Aq&@wxe9~5kmdUQ+L%*wf1!pCB+v+%|37oMGW>1CO_Xf=p|-P#Opq^LVD)3vz!O8(_+55^;0+f8iFtyp*AO6r8K&w@_8N;fF|eBZ4%o|2(#fzy;u@+hyaI>xVfXk+rk zP0XnsFZWok&Hh>QCShk`xy^}Fy1TP$8y-u<%0JY+w@Git&8AR>8GCAyuC=MYtp5Dc z;>5u#iOaXG;N29zT3Kc0G@0z%RXf%l=e#UlvpXd$s(e$Io|{Zj+5Km7p|dPo56|?} znR%irY`)d0#e3L_&Yk?syd*AazQJn`uSemyw+^h{_=4zLrxn? fnb%+a@>%xCuF$Vx?d(awgvsFP>gTe~DWM4fsTN2B diff --git a/examples/pong/resources/paddle_right.png b/examples/pong/resources/paddle_right.png deleted file mode 100644 index d408c5fd66ba31ecb60331a252a7e8f2e8b24a27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683 zcmeAS@N?(olHy`uVBq!ia0vp^l0clo!3HFYLuc0jDbW(wh!W?b)Wnj^{5*w_%-mE4 z_Ujx%f*KZEO!FQB6|k3h`nm#zgt-lbCeECD7bwJ8;1OBOz`*qZgc+UIn9N{cVAAw- zaSW-r^>)^7|Hlpj$I`FQmSFnmYNOKifj_43(o3#?|0g|a>1)#C5RvNYXkRp;eQ)(= z-#rIgS}cS_Jd7`8{E0Z9zdv&N{Fn3RUMz~adzbaJsbO1ybc}5H<`VhUrF}k=1T59> z-~L-0{Py`O^XYf~+&%2&a)942%k1R4H#)0s-c`Mval*=8s`bOCChyOI`=>S@&0S$> zaUkzxnboB`X*XrIY*&BX_4{`vA6x#^Kd-+tAKR$+VO^@O>RU6__I4(ZzW$TjqEh<% z;udCl{rfpHZLgf~x%18Pe7tH7;ygE&Fmcar`1mGOhi8h;d1X6xmV)bVxu)Dd{WFgz zIxR=WDPl$RQi)f0PIew(*jk^xV#47Vf$TTjuP)4S?}&Q+pf)7P*hSI&cz=Un-siX9 z0{gyaD^6T0(5m60$Q9V(B(jJAbD!jq-}-F~0cpA3CqKQj>k1Ir@M}VSjmnMMH}fwC zZ+@v9pC;SjkY@bpu%f8Hzlhr8UvWxXHQ zvCh1+MCM2^yEUXus*#<4@*O+#sr*M|R$5$Zjb>=oIX%F4|wyvBA#O`e3H(yzVu9O_DUJMGgFU28pC zvwF?hQAxvXsecond; + return &myIterator->second; } private : @@ -144,8 +144,8 @@ int main() sf::Text shaderStr; shaderStr.SetFont(font); shaderStr.SetCharacterSize(20); - shaderStr.SetPosition(5.f, 0.f); shaderStr.SetColor(sf::Color(250, 100, 30)); + shaderStr.SetPosition(5.f, 0.f); shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n" "Flower shader: \"" + entityShader.GetName() + "\"\n" "Global shader: \"" + globalShader.GetName() + "\"\n"); @@ -154,8 +154,8 @@ int main() sf::Text infoStr; infoStr.SetFont(font); infoStr.SetCharacterSize(20); - infoStr.SetPosition(5.f, 500.f); infoStr.SetColor(sf::Color(250, 100, 30)); + infoStr.SetPosition(5.f, 500.f); 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" @@ -249,8 +249,8 @@ void DisplayError() // 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)); + error.SetPosition(100.f, 250.f); // Start the game loop while (window.IsOpened()) 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..f20aedd4 100644 --- a/include/SFML/Graphics.hpp +++ b/include/SFML/Graphics.hpp @@ -30,18 +30,26 @@ //////////////////////////////////////////////////////////// #include +#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/src/SFML/Graphics/Matrix3.cpp b/include/SFML/Graphics/BlendMode.hpp similarity index 76% rename from src/SFML/Graphics/Matrix3.cpp rename to include/SFML/Graphics/BlendMode.hpp index 7de4b0f6..448903bd 100644 --- a/src/SFML/Graphics/Matrix3.cpp +++ b/include/SFML/Graphics/BlendMode.hpp @@ -1,40 +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. -// -//////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////// -// 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. +// +//////////////////////////////////////////////////////////// + +#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..fb181948 --- /dev/null +++ b/include/SFML/Graphics/CircleShape.hpp @@ -0,0 +1,129 @@ +//////////////////////////////////////////////////////////// +// +// 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 + /// + /// Creates a circle with a radius of 10. + /// + //////////////////////////////////////////////////////////// + CircleShape(); + + //////////////////////////////////////////////////////////// + /// \brief Set the radius of the circle + /// + /// The default radius of a circle is 10. + /// + /// \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; + +private : + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetOutlinePointsCount() 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 GetOutlinePoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float myRadius; ///< Radius of 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 +/// +/// \see sf::Shape, sf::StarShape, 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..ac0d5be8 --- /dev/null +++ b/include/SFML/Graphics/ConvexShape.hpp @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////// +// +// 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 + /// + /// Creates a default triangle, just so that it's not empty. + /// + //////////////////////////////////////////////////////////// + ConvexShape(); + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the polygon + /// + /// The default number of points of a polygon is 6. + /// + /// \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 + /// + //////////////////////////////////////////////////////////// + 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 + /// + //////////////////////////////////////////////////////////// + Vector2f GetPoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetOutlinePointsCount() 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 GetOutlinePoint(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::StarShape, 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..0e9393f9 --- /dev/null +++ b/include/SFML/Graphics/RectangleShape.hpp @@ -0,0 +1,129 @@ +//////////////////////////////////////////////////////////// +// +// 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 + /// + /// Creates a 10x10 rectangle. + /// + //////////////////////////////////////////////////////////// + RectangleShape(); + + //////////////////////////////////////////////////////////// + /// \brief Set the size of the rectangle + /// + /// The default size of a rectangle is 10x10. + /// + /// \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; + +private : + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetOutlinePointsCount() 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 GetOutlinePoint(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::StarShape, 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..548c09df 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 namespace sf { class Drawable; -class Shader; +class Vertex; //////////////////////////////////////////////////////////// /// \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 : @@ -296,11 +322,9 @@ private : //////////////////////////////////////////////////////////// // 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 + bool myViewChanged; ///< Has the current view changed since last Draw? }; } // namespace sf @@ -328,8 +352,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 b6263d7f..3f5ceaa0 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..94ce1115 100644 --- a/include/SFML/Graphics/Shader.hpp +++ b/include/SFML/Graphics/Shader.hpp @@ -440,15 +440,20 @@ private : /// window.Draw(sprite, shader); /// \endcode /// +/// ... 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 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 +/// made for sprites and shapes. 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. +/// 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,7 +467,7 @@ 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 diff --git a/include/SFML/Graphics/Shape.hpp b/include/SFML/Graphics/Shape.hpp index a183539a..e38c1784 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,124 @@ public : float GetOutlineThickness() const; //////////////////////////////////////////////////////////// - /// \brief Create a new line + /// \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 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. + /// 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 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 Local bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - 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)); + FloatRect GetLocalBounds() const; //////////////////////////////////////////////////////////// - /// \brief Create a new line + /// \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::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. + /// 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 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 Global bounding rectangle of the entity /// //////////////////////////////////////////////////////////// - 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)); - - //////////////////////////////////////////////////////////// - /// \brief Create a new rectangular 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 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. - /// - /// \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 - /// - //////////////////////////////////////////////////////////// - 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)); - - //////////////////////////////////////////////////////////// - /// \brief Create a new rectangular 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::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. - /// - /// \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 - /// - //////////////////////////////////////////////////////////// - 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 Get the number of points defining the shape /// - /// This function precomputes all the internal parameters - /// needed to properly render the shape (center, outline points). + /// This function must be implemented in derived classes. + /// + /// \return Number of points of the shape /// //////////////////////////////////////////////////////////// - void Compile(); + virtual unsigned int GetOutlinePointsCount() const = 0; //////////////////////////////////////////////////////////// - /// \brief Compute the normal of a given 2D segment + /// \brief Get a point of the shape /// - /// \param p1 First point of the segment - /// \param p2 Second point of the segment - /// \param normal Variable to fill with the calculated normal + /// This function must be implemented in derived classes. /// - /// \return False if the normal couldn't be calculated (segment is null) + /// \param index Index of the point to get + /// + /// \return Index-th point of the shape /// //////////////////////////////////////////////////////////// - static bool ComputeNormal(const Vector2f& p1, const Vector2f& p2, Vector2f& normal); + virtual Vector2f GetOutlinePoint(unsigned int index) const = 0; + +private : //////////////////////////////////////////////////////////// - /// \brief Define a simple 2D point with position, normal and colors + /// \brief Draw the shape to a render target + /// + /// \param target Render target to draw to + /// \param states Current render states /// //////////////////////////////////////////////////////////// - struct Point - { - Point(const Vector2f& position = Vector2f(0, 0), const Color& color = Color(255, 255, 255), const Color& outlineColor = Color(255, 255, 255)); + virtual void Draw(RenderTarget& target, RenderStates states) const; - Vector2f Position; ///< Position - Vector2f Normal; ///< Extruded normal - Color Col; ///< Color of the point - Color OutlineCol; ///< Outline color of the point - }; + //////////////////////////////////////////////////////////// + /// \brief Update the fill vertices' color + /// + //////////////////////////////////////////////////////////// + void UpdateFillColors(); + + //////////////////////////////////////////////////////////// + /// \brief Update the fill vertices' texture coordinates + /// + //////////////////////////////////////////////////////////// + void UpdateTexCoords(); + + //////////////////////////////////////////////////////////// + /// \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 +317,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 cb754797..675a920f 100644 --- a/include/SFML/Graphics/Sprite.hpp +++ b/include/SFML/Graphics/Sprite.hpp @@ -28,8 +28,9 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include #include +#include +#include #include @@ -39,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 : @@ -57,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 /// @@ -70,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. /// @@ -166,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 //////////////////////////////////////////////////////////// - ResourcePtr 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 @@ -223,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. @@ -237,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). /// @@ -254,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/StarShape.hpp b/include/SFML/Graphics/StarShape.hpp new file mode 100644 index 00000000..c906a5b8 --- /dev/null +++ b/include/SFML/Graphics/StarShape.hpp @@ -0,0 +1,178 @@ +//////////////////////////////////////////////////////////// +// +// 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_STARSHAPE_HPP +#define SFML_STARSHAPE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Specialized shape representing a star +/// +//////////////////////////////////////////////////////////// +class SFML_API StarShape : public Shape +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + /// Creates a star with 5 points, an inner radius of 10 and + /// an outer radius of 20. + /// + //////////////////////////////////////////////////////////// + StarShape(); + + //////////////////////////////////////////////////////////// + /// \brief Set the inner radius of the star + /// + /// The default inner radius of a star is 10. + /// + /// \param radius New inner radius of the star + /// + /// \see GetInnerRadius + /// + //////////////////////////////////////////////////////////// + void SetInnerRadius(float radius); + + //////////////////////////////////////////////////////////// + /// \brief Get the inner radius of the star + /// + /// \return Inner radius of the star + /// + /// \see SetInnerRadius + /// + //////////////////////////////////////////////////////////// + float GetInnerRadius() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the outer radius of the star + /// + /// The default outer radius of a star is 20. + /// + /// \param radius New outer radius of the star + /// + /// \see GetOuterRadius + /// + //////////////////////////////////////////////////////////// + void SetOuterRadius(float radius); + + //////////////////////////////////////////////////////////// + /// \brief Get the outer radius of the star + /// + /// \return Outer radius of the star + /// + /// \see SetOuterRadius + /// + //////////////////////////////////////////////////////////// + float GetOuterRadius() const; + + //////////////////////////////////////////////////////////// + /// \brief Set the number of points of the star + /// + /// The default number of points of a star is 5. + /// + /// \param count New number of points of the star + /// + /// \see GetPointsCount + /// + //////////////////////////////////////////////////////////// + void SetPointsCount(unsigned int count); + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points of the star + /// + /// \return Number of points of the star + /// + /// \see SetPointsCount + /// + //////////////////////////////////////////////////////////// + unsigned int GetPointsCount() const; + +private : + + //////////////////////////////////////////////////////////// + /// \brief Get the number of points defining the shape + /// + /// \return Number of points of the shape + /// + //////////////////////////////////////////////////////////// + virtual unsigned int GetOutlinePointsCount() 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 GetOutlinePoint(unsigned int index) const; + +private : + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + float myInnerRadius; ///< Inner radius of the star + float myOuterRadius; ///< Outer radius of the star + unsigned int myPointsCount; ///< Number of points of the star +}; + +} // namespace sf + + +#endif // SFML_STARSHAPE_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::StarShape +/// \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::StarShape star; +/// star.SetInnerRadius(25); +/// star.SetInnerRadius(40); +/// star.SetPointsCount(6); +/// star.SetOutlineColor(sf::Color::Red); +/// star.SetOutlineThickness(5); +/// star.SetPosition(10, 20); +/// ... +/// window.Draw(star); +/// \endcode +/// +/// \see sf::Shape, sf::CircleShape, sf::RectangleShape, sf::ConvexShape +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Text.hpp b/include/SFML/Graphics/Text.hpp index 1aa45aa7..47f35f8e 100644 --- a/include/SFML/Graphics/Text.hpp +++ b/include/SFML/Graphics/Text.hpp @@ -28,12 +28,14 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#include #include #include +#include #include #include +#include #include +#include namespace sf @@ -42,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 : @@ -100,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(). /// @@ -136,6 +144,18 @@ public : //////////////////////////////////////////////////////////// void SetStyle(unsigned long 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 /// @@ -188,14 +208,23 @@ public : //////////////////////////////////////////////////////////// unsigned long 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. /// @@ -204,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 - ResourcePtr myFont; ///< Font used to display the string - unsigned int myCharacterSize; ///< Base size of characters, in pixels - unsigned long 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 + unsigned long myStyle; ///< Text style (see the 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 @@ -259,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 @@ -294,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 f4a2a276..b4d9a109 100644 --- a/include/SFML/Graphics/Texture.hpp +++ b/include/SFML/Graphics/Texture.hpp @@ -46,6 +46,18 @@ class InputStream; //////////////////////////////////////////////////////////// class SFML_API Texture : public Resource, 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 : //////////////////////////////////////////////////////////// @@ -354,12 +366,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 @@ -388,18 +411,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 @@ -452,6 +495,7 @@ 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 }; @@ -515,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..17459989 --- /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..d20a16a2 --- /dev/null +++ b/include/SFML/Graphics/Transformable.hpp @@ -0,0 +1,414 @@ +//////////////////////////////////////////////////////////// +// +// 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 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 + /// + /// \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 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 + /// + /// \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 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..21ff96ea --- /dev/null +++ b/include/SFML/Graphics/Vertex.hpp @@ -0,0 +1,143 @@ +//////////////////////////////////////////////////////////// +// +// 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 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 Vector2i& 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 Color& color, const Vector2i& texCoords); + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + Vector2f Position; ///< 2D position of the vertex + sf::Color Color; ///< Color of the vertex + Vector2i 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::Vector2i( 0, 0)), +/// sf::Vertex(sf::Vector2f( 0, 100), sf::Color::Red, sf::Vector2i( 0, 10)), +/// sf::Vertex(sf::Vector2f(100, 100), sf::Color::Red, sf::Vector2i(10, 10)), +/// sf::Vertex(sf::Vector2f(100, 0), sf::Color::Red, sf::Vector2i(10, 0)) +/// }; +/// +/// // draw it +/// window.Draw(vertices, 4, sf::Quads); +/// \endcode +/// +/// \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/include/SFML/Window/Context.hpp b/include/SFML/Window/Context.hpp index def5acf9..48b21491 100644 --- a/include/SFML/Window/Context.hpp +++ b/include/SFML/Window/Context.hpp @@ -41,6 +41,8 @@ namespace priv class GlContext; } +typedef void* ContextId; + //////////////////////////////////////////////////////////// /// \brief Class holding a valid drawing context /// @@ -75,6 +77,18 @@ public : //////////////////////////////////////////////////////////// bool SetActive(bool active); + //////////////////////////////////////////////////////////// + /// \brief Return the identifier of the current active context + /// + /// The returned id has no special meaning, it should only be + /// used as a key to map external stuff to internal contexts. + /// This function returns 0 if no context is active. + /// + /// \return Identifier of the current context + /// + //////////////////////////////////////////////////////////// + static ContextId GetCurrentContextId(); + public : //////////////////////////////////////////////////////////// diff --git a/src/SFML/Graphics/CMakeLists.txt b/src/SFML/Graphics/CMakeLists.txt index 09daa851..1a87fd40 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}/StarShape.cpp + ${INCROOT}/StarShape.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}/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..86a6a3cb --- /dev/null +++ b/src/SFML/Graphics/CircleShape.cpp @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////// +// +// 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() : +myRadius(10) +{ +} + + +//////////////////////////////////////////////////////////// +void CircleShape::SetRadius(float radius) +{ + myRadius = radius; + Update(); +} + + +//////////////////////////////////////////////////////////// +float CircleShape::GetRadius() const +{ + return myRadius; +} + + +//////////////////////////////////////////////////////////// +unsigned int CircleShape::GetOutlinePointsCount() const +{ + return 30; +} + + +//////////////////////////////////////////////////////////// +Vector2f CircleShape::GetOutlinePoint(unsigned int index) const +{ + float angle = index * 2 * 3.141592654f / GetOutlinePointsCount(); + 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..222d5367 --- /dev/null +++ b/src/SFML/Graphics/ConvexShape.cpp @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////// +// +// 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() +{ + // Let's define a triangle by default... just so that it's not empty + SetPointsCount(3); + SetPoint(0, Vector2f(5, 0)); + SetPoint(1, Vector2f(0, 10)); + SetPoint(2, Vector2f(10, 10)); +} + + +//////////////////////////////////////////////////////////// +void ConvexShape::SetPointsCount(unsigned int count) +{ + myPoints.resize(count); +} + + +//////////////////////////////////////////////////////////// +unsigned int ConvexShape::GetPointsCount() const +{ + return myPoints.size(); +} + + +//////////////////////////////////////////////////////////// +void ConvexShape::SetPoint(unsigned int index, const Vector2f& point) +{ + myPoints[index] = point; +} + + +//////////////////////////////////////////////////////////// +Vector2f ConvexShape::GetPoint(unsigned int index) const +{ + return myPoints[index]; +} + + +//////////////////////////////////////////////////////////// +unsigned int ConvexShape::GetOutlinePointsCount() const +{ + return GetPointsCount(); +} + + +//////////////////////////////////////////////////////////// +Vector2f ConvexShape::GetOutlinePoint(unsigned int index) const +{ + return GetPoint(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 5bc51c83..8e8ffc72 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -452,7 +452,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; @@ -493,10 +493,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/RectangleShape.cpp b/src/SFML/Graphics/RectangleShape.cpp new file mode 100644 index 00000000..ba8d0ebf --- /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() : +mySize(10, 10) +{ +} + + +//////////////////////////////////////////////////////////// +void RectangleShape::SetSize(const Vector2f& size) +{ + mySize = size; + Update(); +} + + +//////////////////////////////////////////////////////////// +const Vector2f& RectangleShape::GetSize() const +{ + return mySize; +} + + +//////////////////////////////////////////////////////////// +unsigned int RectangleShape::GetOutlinePointsCount() const +{ + return 4; +} + + +//////////////////////////////////////////////////////////// +Vector2f RectangleShape::GetOutlinePoint(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..4d8d593f 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 (), +myViewChanged(false) { - } //////////////////////////////////////////////////////////// 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; + myViewChanged = true; } //////////////////////////////////////////////////////////// const View& RenderTarget::GetView() const { - return myCurrentView; + return myView; } @@ -175,35 +115,159 @@ 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; + // Apply the new view if needed + if (myViewChanged) + { + // Set the viewport + IntRect viewport = GetViewport(myView); + int top = GetHeight() - (viewport.Top + viewport.Height); + GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height)); - // Restore the render states and the current view, for SFML rendering - myRenderer.Initialize(); - SetView(GetView()); + // Set the projection matrix + GLCheck(glMatrixMode(GL_PROJECTION)); + GLCheck(glLoadMatrixf(myView.GetTransform().GetMatrix())); + + myViewChanged = false; + } + + // Apply the transform + GLCheck(glMatrixMode(GL_MODELVIEW)); + GLCheck(glLoadMatrixf(states.Transform.GetMatrix())); + + // Apply the blend mode + switch (states.BlendMode) + { + // 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; + } + + // Apply the texture + if (states.Texture) + states.Texture->Bind(Texture::Pixels); + else + GLCheck(glBindTexture(GL_TEXTURE_2D, 0)); + + // Apply the shader + if (states.Shader) + states.Shader->Bind(); + else + GLCheck(glUseProgramObjectARB(0)); + + // Setup the pointers to the vertices' components + 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_INT, 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)); } } //////////////////////////////////////////////////////////// -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(); + + 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(glEnableClientState(GL_VERTEX_ARRAY)); + GLCheck(glEnableClientState(GL_COLOR_ARRAY)); + GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + + SetView(GetView()); } } @@ -215,9 +279,8 @@ void RenderTarget::Initialize() myDefaultView.Reset(FloatRect(0, 0, static_cast(GetWidth()), static_cast(GetHeight()))); SetView(myDefaultView); - // Initialize the renderer - if (Activate(true)) - myRenderer.Initialize(); + // Initialize the default OpenGL render-states + ResetGLStates(); } } // namespace sf 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 e5c62fd6..7cdc3ea2 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -371,7 +371,7 @@ bool Shader::CompileProgram() static const char* vertexSrc = "void main()" "{" - " gl_TexCoord[0] = gl_MultiTexCoord0;" + " gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;" " gl_FrontColor = gl_Color;" " gl_Position = ftransform();" "}"; diff --git a/src/SFML/Graphics/Shape.cpp b/src/SFML/Graphics/Shape.cpp index ed80496f..9e17e439 100644 --- a/src/SFML/Graphics/Shape.cpp +++ b/src/SFML/Graphics/Shape.cpp @@ -26,365 +26,271 @@ // 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 offseted } //////////////////////////////////////////////////////////// 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 = GetOutlinePointsCount(); + 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) + sf::Err() << "Invalid shape: it has less than 3 points" << std::endl; + 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 + Vector2f offset(myOutlineThickness, myOutlineThickness); + for (unsigned int i = 0; i < count; ++i) + myVertices[i + 1].Position = GetOutlinePoint(i) + offset; + myVertices[count + 1].Position = myVertices[1].Position; + + // Update the bounding rectangle + 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 = static_cast(myTextureRect.Left + myTextureRect.Width * xratio); + myVertices[i].TexCoords.y = static_cast(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 19405a7b..23ac67a8 100644 --- a/src/SFML/Graphics/Sprite.cpp +++ b/src/SFML/Graphics/Sprite.cpp @@ -27,46 +27,44 @@ //////////////////////////////////////////////////////////// #include #include -#include -#include +#include namespace sf { //////////////////////////////////////////////////////////// Sprite::Sprite() : -Drawable (), -mySubRect (0, 0, 1, 1), -myIsFlippedX(false), -myIsFlippedY(false) +myTexture (NULL), +myTextureRect(0, 0, 0, 0) { - } //////////////////////////////////////////////////////////// Sprite::Sprite(const Texture& texture) : -Drawable (), -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; @@ -74,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; } @@ -117,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() +{ + int left = myTextureRect.Left; + int right = myTextureRect.Left + myTextureRect.Width; + int top = myTextureRect.Top; + int bottom = myTextureRect.Top + myTextureRect.Height; + + myVertices[0].TexCoords = Vector2i(left, top); + myVertices[1].TexCoords = Vector2i(left, bottom); + myVertices[2].TexCoords = Vector2i(right, bottom); + myVertices[3].TexCoords = Vector2i(right, top); } } // namespace sf diff --git a/src/SFML/Graphics/StarShape.cpp b/src/SFML/Graphics/StarShape.cpp new file mode 100644 index 00000000..0f5696ef --- /dev/null +++ b/src/SFML/Graphics/StarShape.cpp @@ -0,0 +1,107 @@ +//////////////////////////////////////////////////////////// +// +// 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 +{ +//////////////////////////////////////////////////////////// +StarShape::StarShape() : +myInnerRadius(10), +myOuterRadius(20), +myPointsCount(5) +{ +} + + +//////////////////////////////////////////////////////////// +void StarShape::SetInnerRadius(float radius) +{ + myInnerRadius = radius; + Update(); +} + + +//////////////////////////////////////////////////////////// +float StarShape::GetInnerRadius() const +{ + return myInnerRadius; +} + + +//////////////////////////////////////////////////////////// +void StarShape::SetOuterRadius(float radius) +{ + myOuterRadius = radius; + Update(); +} + + +//////////////////////////////////////////////////////////// +float StarShape::GetOuterRadius() const +{ + return myOuterRadius; +} + + +//////////////////////////////////////////////////////////// +void StarShape::SetPointsCount(unsigned int count) +{ + myPointsCount = count; + Update(); +} + + +//////////////////////////////////////////////////////////// +unsigned int StarShape::GetPointsCount() const +{ + return myPointsCount; +} + + +//////////////////////////////////////////////////////////// +unsigned int StarShape::GetOutlinePointsCount() const +{ + return myPointsCount * 2; +} + + +//////////////////////////////////////////////////////////// +Vector2f StarShape::GetOutlinePoint(unsigned int index) const +{ + static const float pi = 3.141592654f; + float angle = index * pi / myPointsCount - pi / 2; + float x = std::cos(angle); + float y = std::sin(angle); + float radius = (index % 2 == 0 ? myOuterRadius : myInnerRadius); + + return Vector2f(myOuterRadius + x * radius, myOuterRadius + y * radius); +} + +} // namespace sf diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index bed9c5e2..cec99882 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(unsigned long 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 @@ unsigned long 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, Vector2i(1, 1))); + myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2i(2, 1))); + myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2i(2, 2))); + myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2i(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(); + int u1 = glyph.TextureRect.Left; + int v1 = glyph.TextureRect.Top; + int u2 = glyph.TextureRect.Left + glyph.TextureRect.Width; + int v2 = glyph.TextureRect.Top + glyph.TextureRect.Height; + + // Add a quad for the current character + myVertices.Append(Vertex(Vector2f(x + left - italic * top, y + top), myColor, Vector2i(u1, v1))); + myVertices.Append(Vertex(Vector2f(x + right - italic * top, y + top), myColor, Vector2i(u2, v1))); + myVertices.Append(Vertex(Vector2f(x + right - italic * bottom, y + bottom), myColor, Vector2i(u2, v2))); + myVertices.Append(Vertex(Vector2f(x + left - italic * bottom, y + bottom), myColor, Vector2i(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, Vector2i(1, 1))); + myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2i(2, 1))); + myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2i(2, 2))); + myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2i(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 e623e325..0c07cf34 100644 --- a/src/SFML/Graphics/Texture.cpp +++ b/src/SFML/Graphics/Texture.cpp @@ -44,6 +44,7 @@ myTextureWidth (0), myTextureHeight(0), myTexture (0), myIsSmooth (false), +myIsRepeated (false), myPixelsFlipped(false) { @@ -59,6 +60,7 @@ myTextureWidth (0), myTextureHeight(0), myTexture (0), myIsSmooth (copy.myIsSmooth), +myIsRepeated (copy.myIsRepeated), myPixelsFlipped(false) { LoadFromImage(copy.CopyToImage()); @@ -124,8 +126,8 @@ bool Texture::Create(unsigned int width, unsigned int height) // 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)); @@ -347,9 +349,38 @@ void Texture::Update(const Window& window, unsigned int x, unsigned int y) //////////////////////////////////////////////////////////// -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)); + } } @@ -380,32 +411,28 @@ 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(); + + 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,6 +459,7 @@ 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); return *this; diff --git a/src/SFML/Graphics/Transform.cpp b/src/SFML/Graphics/Transform.cpp new file mode 100644 index 00000000..181e1bbd --- /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 Transform(); + } +} + + +//////////////////////////////////////////////////////////// +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..31130bac --- /dev/null +++ b/src/SFML/Graphics/Transformable.cpp @@ -0,0 +1,210 @@ +//////////////////////////////////////////////////////////// +// +// 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) +{ +} + + +//////////////////////////////////////////////////////////// +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..43cf1905 --- /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 Vector2i& texCoords) : +Position (position), +Color (255, 255, 255), +TexCoords(texCoords) +{ +} + + +//////////////////////////////////////////////////////////// +Vertex::Vertex(const Vector2f& position, const sf::Color& color, const Vector2i& 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 diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp index 961c2508..354b4cdc 100644 --- a/src/SFML/Window/Context.cpp +++ b/src/SFML/Window/Context.cpp @@ -53,6 +53,13 @@ bool Context::SetActive(bool active) } +//////////////////////////////////////////////////////////// +ContextId Context::GetCurrentContextId() +{ + return priv::GlContext::GetCurrentContext(); +} + + //////////////////////////////////////////////////////////// Context::Context(const ContextSettings& settings, unsigned int width, unsigned int height) { diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 196ed9c8..51f808ae 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -177,6 +177,13 @@ GlContext* GlContext::New(const ContextSettings& settings, unsigned int width, u } +//////////////////////////////////////////////////////////// +GlContext* GlContext::GetCurrentContext() +{ + return currentContext; +} + + //////////////////////////////////////////////////////////// GlContext::~GlContext() { diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index f6eb193a..015ef72a 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -118,6 +118,16 @@ public : //////////////////////////////////////////////////////////// static GlContext* New(const ContextSettings& settings, unsigned int width, unsigned int height); + //////////////////////////////////////////////////////////// + /// \brief Return the current active context + /// + /// This function returns 0 if no context is active. + /// + /// \return Context currently active in this thread + /// + //////////////////////////////////////////////////////////// + static GlContext* GetCurrentContext(); + public : ////////////////////////////////////////////////////////////