diff --git a/include/SFML/Graphics/CoordinateType.hpp b/include/SFML/Graphics/CoordinateType.hpp new file mode 100644 index 000000000..42c6cd020 --- /dev/null +++ b/include/SFML/Graphics/CoordinateType.hpp @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2023 Laurent Gomila (laurent@sfml-dev.org) +// +// 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. +// +//////////////////////////////////////////////////////////// + +#pragma once + +namespace sf +{ + +//////////////////////////////////////////////////////////// +/// \ingroup graphics +/// \brief Types of texture coordinates that can be used for rendering +/// +/// \see sf::Texture::bind +/// +//////////////////////////////////////////////////////////// +enum class CoordinateType +{ + Normalized, //!< Texture coordinates in range [0 .. 1] + Pixels //!< Texture coordinates in range [0 .. size] +}; + +} // namespace sf diff --git a/include/SFML/Graphics/RenderStates.hpp b/include/SFML/Graphics/RenderStates.hpp index 7f58bbeb4..3cc677c6a 100644 --- a/include/SFML/Graphics/RenderStates.hpp +++ b/include/SFML/Graphics/RenderStates.hpp @@ -30,6 +30,7 @@ #include #include +#include #include @@ -93,13 +94,18 @@ struct SFML_GRAPHICS_API RenderStates //////////////////////////////////////////////////////////// /// \brief Construct a set of render states with all its attributes /// - /// \param theBlendMode Blend mode to use - /// \param theTransform Transform to use - /// \param theTexture Texture to use - /// \param theShader Shader to use + /// \param theBlendMode Blend mode to use + /// \param theTransform Transform to use + /// \param theCoordinateType Texture coordinate type to use + /// \param theTexture Texture to use + /// \param theShader Shader to use /// //////////////////////////////////////////////////////////// - RenderStates(const BlendMode& theBlendMode, const Transform& theTransform, const Texture* theTexture, const Shader* theShader); + RenderStates(const BlendMode& theBlendMode, + const Transform& theTransform, + CoordinateType theCoordinateType, + const Texture* theTexture, + const Shader* theShader); //////////////////////////////////////////////////////////// // Static member data @@ -110,10 +116,11 @@ struct SFML_GRAPHICS_API RenderStates //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - BlendMode blendMode{BlendAlpha}; //!< Blending mode - Transform transform; //!< Transform - const Texture* texture{}; //!< Texture - const Shader* shader{}; //!< Shader + BlendMode blendMode{BlendAlpha}; //!< Blending mode + Transform transform; //!< Transform + CoordinateType coordinateType{CoordinateType::Pixels}; //!< Texture coordinate type + const Texture* texture{}; //!< Texture + const Shader* shader{}; //!< Shader }; } // namespace sf @@ -123,10 +130,11 @@ struct SFML_GRAPHICS_API RenderStates /// \class sf::RenderStates /// \ingroup graphics /// -/// There are four global states that can be applied to +/// There are five 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 coordinate type: how texture coordinates are interpreted /// \li the texture: what image is mapped to the object /// \li the shader: what custom effect is applied to the object /// diff --git a/include/SFML/Graphics/RenderTarget.hpp b/include/SFML/Graphics/RenderTarget.hpp index 49eaabcca..06f9166dc 100644 --- a/include/SFML/Graphics/RenderTarget.hpp +++ b/include/SFML/Graphics/RenderTarget.hpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -462,10 +463,11 @@ private: //////////////////////////////////////////////////////////// /// \brief Apply a new texture /// - /// \param texture Texture to apply + /// \param texture Texture to apply + /// \param coordinateType The texture coordinate type to use /// //////////////////////////////////////////////////////////// - void applyTexture(const Texture* texture); + void applyTexture(const Texture* texture, CoordinateType coordinateType = CoordinateType::Pixels); //////////////////////////////////////////////////////////// /// \brief Apply a new shader @@ -514,6 +516,7 @@ private: bool scissorEnabled; //!< Is scissor testing enabled? BlendMode lastBlendMode; //!< Cached blending mode std::uint64_t lastTextureId; //!< Cached texture + CoordinateType lastCoordinateType; //!< Texture coordinate type bool texCoordsArrayEnabled; //!< Is GL_TEXTURE_COORD_ARRAY client state enabled? bool useVertexCache; //!< Did we previously use the vertex cache? std::array vertexCache; //!< Pre-transformed vertices cache diff --git a/include/SFML/Graphics/Texture.hpp b/include/SFML/Graphics/Texture.hpp index 9d4137c97..3bfb1b9bb 100644 --- a/include/SFML/Graphics/Texture.hpp +++ b/include/SFML/Graphics/Texture.hpp @@ -29,6 +29,7 @@ //////////////////////////////////////////////////////////// #include +#include #include #include @@ -52,16 +53,6 @@ class Image; class SFML_GRAPHICS_API Texture : GlResource { public: - //////////////////////////////////////////////////////////// - /// \brief Types of texture coordinates that can be used for rendering - /// - //////////////////////////////////////////////////////////// - enum CoordinateType - { - Normalized, //!< Texture coordinates in range [0 .. 1] - Pixels //!< Texture coordinates in range [0 .. size] - }; - //////////////////////////////////////////////////////////// /// \brief Default constructor /// @@ -578,7 +569,7 @@ public: /// \param coordinateType Type of texture coordinates to use /// //////////////////////////////////////////////////////////// - static void bind(const Texture* texture, CoordinateType coordinateType = Normalized); + static void bind(const Texture* texture, CoordinateType coordinateType = CoordinateType::Normalized); //////////////////////////////////////////////////////////// /// \brief Get the maximum texture size allowed diff --git a/src/SFML/Graphics/CMakeLists.txt b/src/SFML/Graphics/CMakeLists.txt index 3e727fbdc..229872f84 100644 --- a/src/SFML/Graphics/CMakeLists.txt +++ b/src/SFML/Graphics/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRC ${INCROOT}/BlendMode.hpp ${INCROOT}/Color.hpp ${INCROOT}/Color.inl + ${INCROOT}/CoordinateType.hpp ${INCROOT}/Export.hpp ${SRCROOT}/Font.cpp ${INCROOT}/Font.hpp diff --git a/src/SFML/Graphics/RenderStates.cpp b/src/SFML/Graphics/RenderStates.cpp index 21b566442..be33184ac 100644 --- a/src/SFML/Graphics/RenderStates.cpp +++ b/src/SFML/Graphics/RenderStates.cpp @@ -71,10 +71,12 @@ RenderStates::RenderStates(const Shader* theShader) : shader(theShader) //////////////////////////////////////////////////////////// RenderStates::RenderStates(const BlendMode& theBlendMode, const Transform& theTransform, + CoordinateType theCoordinateType, const Texture* theTexture, const Shader* theShader) : blendMode(theBlendMode), transform(theTransform), +coordinateType(theCoordinateType), texture(theTexture), shader(theShader) { diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 0d6354533..fdc218873 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -676,11 +676,12 @@ void RenderTarget::applyTransform(const Transform& transform) //////////////////////////////////////////////////////////// -void RenderTarget::applyTexture(const Texture* texture) +void RenderTarget::applyTexture(const Texture* texture, CoordinateType coordinateType) { - Texture::bind(texture, Texture::Pixels); + Texture::bind(texture, coordinateType); - m_cache.lastTextureId = texture ? texture->m_cacheId : 0; + m_cache.lastTextureId = texture ? texture->m_cacheId : 0; + m_cache.lastCoordinateType = coordinateType; } @@ -740,13 +741,13 @@ void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states) // This saves us from having to call glFlush() in // RenderTextureImplFBO which can be quite costly // See: https://www.khronos.org/opengl/wiki/Memory_Model - applyTexture(states.texture); + applyTexture(states.texture, states.coordinateType); } else { const std::uint64_t textureId = states.texture ? states.texture->m_cacheId : 0; - if (textureId != m_cache.lastTextureId) - applyTexture(states.texture); + if (textureId != m_cache.lastTextureId || states.coordinateType != m_cache.lastCoordinateType) + applyTexture(states.texture, states.coordinateType); } // Apply the shader diff --git a/src/SFML/Graphics/Shape.cpp b/src/SFML/Graphics/Shape.cpp index 1b1bdd280..1c2fbf72d 100644 --- a/src/SFML/Graphics/Shape.cpp +++ b/src/SFML/Graphics/Shape.cpp @@ -236,6 +236,7 @@ void Shape::draw(RenderTarget& target, const RenderStates& states) const RenderStates statesCopy(states); statesCopy.transform *= getTransform(); + statesCopy.coordinateType = CoordinateType::Pixels; // Render the inside statesCopy.texture = m_texture; diff --git a/src/SFML/Graphics/Sprite.cpp b/src/SFML/Graphics/Sprite.cpp index 76d9e96fd..c4528e9ba 100644 --- a/src/SFML/Graphics/Sprite.cpp +++ b/src/SFML/Graphics/Sprite.cpp @@ -131,7 +131,8 @@ void Sprite::draw(RenderTarget& target, const RenderStates& states) const RenderStates statesCopy(states); statesCopy.transform *= getTransform(); - statesCopy.texture = m_texture; + statesCopy.texture = m_texture; + statesCopy.coordinateType = CoordinateType::Pixels; target.draw(m_vertices.data(), m_vertices.size(), PrimitiveType::TriangleStrip, statesCopy); } diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index a9cd0a4a2..7f922e752 100644 --- a/src/SFML/Graphics/Text.cpp +++ b/src/SFML/Graphics/Text.cpp @@ -355,7 +355,8 @@ void Text::draw(RenderTarget& target, const RenderStates& states) const RenderStates statesCopy(states); statesCopy.transform *= getTransform(); - statesCopy.texture = &m_font->getTexture(m_characterSize); + statesCopy.texture = &m_font->getTexture(m_characterSize); + statesCopy.coordinateType = CoordinateType::Pixels; // Only draw the outline if there is something to draw if (m_outlineThickness != 0) diff --git a/src/SFML/Graphics/Texture.cpp b/src/SFML/Graphics/Texture.cpp index a4b373c01..301d2be44 100644 --- a/src/SFML/Graphics/Texture.cpp +++ b/src/SFML/Graphics/Texture.cpp @@ -862,7 +862,7 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType) glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture)); // Check if we need to define a special texture matrix - if ((coordinateType == Pixels) || texture->m_pixelsFlipped) + if ((coordinateType == CoordinateType::Pixels) || texture->m_pixelsFlipped) { // clang-format off GLfloat matrix[16] = {1.f, 0.f, 0.f, 0.f, @@ -873,7 +873,7 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType) // 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) + if (coordinateType == CoordinateType::Pixels) { matrix[0] = 1.f / static_cast(texture->m_actualSize.x); matrix[5] = 1.f / static_cast(texture->m_actualSize.y); @@ -889,10 +889,16 @@ void Texture::bind(const Texture* texture, CoordinateType coordinateType) // Load the matrix glCheck(glMatrixMode(GL_TEXTURE)); glCheck(glLoadMatrixf(matrix)); - - // Go back to model-view mode (sf::RenderTarget relies on it) - glCheck(glMatrixMode(GL_MODELVIEW)); } + else + { + // Reset the texture matrix + glCheck(glMatrixMode(GL_TEXTURE)); + glCheck(glLoadIdentity()); + } + + // Go back to model-view mode (sf::RenderTarget relies on it) + glCheck(glMatrixMode(GL_MODELVIEW)); } else { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a8c397f3c..2601b71a3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -85,6 +85,7 @@ set(GRAPHICS_SRC Graphics/CircleShape.test.cpp Graphics/Color.test.cpp Graphics/ConvexShape.test.cpp + Graphics/CoordinateType.test.cpp Graphics/Drawable.test.cpp Graphics/Font.test.cpp Graphics/Glyph.test.cpp diff --git a/test/Graphics/CoordinateType.test.cpp b/test/Graphics/CoordinateType.test.cpp new file mode 100644 index 000000000..b3e69cccd --- /dev/null +++ b/test/Graphics/CoordinateType.test.cpp @@ -0,0 +1,16 @@ +#include + +#include + +#include + +TEST_CASE("[Graphics] sf::CoordinateType") +{ + SECTION("Type traits") + { + STATIC_CHECK(std::is_copy_constructible_v); + STATIC_CHECK(std::is_copy_assignable_v); + STATIC_CHECK(std::is_nothrow_move_constructible_v); + STATIC_CHECK(std::is_nothrow_move_assignable_v); + } +} diff --git a/test/Graphics/RenderStates.test.cpp b/test/Graphics/RenderStates.test.cpp index 25c69c4e4..2a8b743e6 100644 --- a/test/Graphics/RenderStates.test.cpp +++ b/test/Graphics/RenderStates.test.cpp @@ -22,6 +22,7 @@ TEST_CASE("[Graphics] sf::RenderStates") const sf::RenderStates renderStates; CHECK(renderStates.blendMode == sf::BlendMode()); CHECK(renderStates.transform == sf::Transform()); + CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels); CHECK(renderStates.texture == nullptr); CHECK(renderStates.shader == nullptr); } @@ -37,6 +38,7 @@ TEST_CASE("[Graphics] sf::RenderStates") const sf::RenderStates renderStates(blendMode); CHECK(renderStates.blendMode == blendMode); CHECK(renderStates.transform == sf::Transform()); + CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels); CHECK(renderStates.texture == nullptr); CHECK(renderStates.shader == nullptr); } @@ -47,6 +49,7 @@ TEST_CASE("[Graphics] sf::RenderStates") const sf::RenderStates renderStates(transform); CHECK(renderStates.blendMode == sf::BlendMode()); CHECK(renderStates.transform == transform); + CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels); CHECK(renderStates.texture == nullptr); CHECK(renderStates.shader == nullptr); } @@ -57,6 +60,7 @@ TEST_CASE("[Graphics] sf::RenderStates") const sf::RenderStates renderStates(texture); CHECK(renderStates.blendMode == sf::BlendMode()); CHECK(renderStates.transform == sf::Transform()); + CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels); CHECK(renderStates.texture == texture); CHECK(renderStates.shader == nullptr); } @@ -67,6 +71,7 @@ TEST_CASE("[Graphics] sf::RenderStates") const sf::RenderStates renderStates(shader); CHECK(renderStates.blendMode == sf::BlendMode()); CHECK(renderStates.transform == sf::Transform()); + CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels); CHECK(renderStates.texture == nullptr); CHECK(renderStates.shader == shader); } @@ -80,9 +85,10 @@ TEST_CASE("[Graphics] sf::RenderStates") sf::BlendMode::DstAlpha, sf::BlendMode::Max); const sf::Transform transform(10, 2, 3, 4, 50, 40, 30, 20, 10); - const sf::RenderStates renderStates(blendMode, transform, nullptr, nullptr); + const sf::RenderStates renderStates(blendMode, transform, sf::CoordinateType::Normalized, nullptr, nullptr); CHECK(renderStates.blendMode == blendMode); CHECK(renderStates.transform == transform); + CHECK(renderStates.coordinateType == sf::CoordinateType::Normalized); CHECK(renderStates.texture == nullptr); CHECK(renderStates.shader == nullptr); } @@ -92,6 +98,7 @@ TEST_CASE("[Graphics] sf::RenderStates") { CHECK(sf::RenderStates::Default.blendMode == sf::BlendMode()); CHECK(sf::RenderStates::Default.transform == sf::Transform()); + CHECK(sf::RenderStates::Default.coordinateType == sf::CoordinateType::Pixels); CHECK(sf::RenderStates::Default.texture == nullptr); CHECK(sf::RenderStates::Default.shader == nullptr); }