diff --git a/include/SFML/Graphics/RenderTarget.hpp b/include/SFML/Graphics/RenderTarget.hpp index 0d167460..a545f3df 100644 --- a/include/SFML/Graphics/RenderTarget.hpp +++ b/include/SFML/Graphics/RenderTarget.hpp @@ -129,6 +129,21 @@ public: //////////////////////////////////////////////////////////// IntRect getViewport(const View& view) const; + //////////////////////////////////////////////////////////// + /// \brief Get the scissor rectangle of a view, applied to this render target + /// + /// The scissor rectangle is defined in the view as a ratio, this + /// function simply applies this ratio to the current dimensions + /// of the render target to calculate the pixels rectangle + /// that the scissor rectangle actually covers in the target. + /// + /// \param view The view for which we want to compute the scissor rectangle + /// + /// \return Scissor rectangle, expressed in pixels + /// + //////////////////////////////////////////////////////////// + IntRect getScissor(const View& view) const; + //////////////////////////////////////////////////////////// /// \brief Convert a point from target coordinates to world /// coordinates, using the current view @@ -461,6 +476,7 @@ private: bool enable; ///< Is the cache enabled? bool glStatesSet; ///< Are our internal GL states set yet? bool viewChanged; ///< Has the current view changed since last draw? + bool scissorEnabled; ///< Is scissor testing enabled? BlendMode lastBlendMode; ///< Cached blending mode Uint64 lastTextureId; ///< Cached texture bool texCoordsArrayEnabled; ///< Is GL_TEXTURE_COORD_ARRAY client state enabled? diff --git a/include/SFML/Graphics/View.hpp b/include/SFML/Graphics/View.hpp index a3faa6e0..9831a1de 100644 --- a/include/SFML/Graphics/View.hpp +++ b/include/SFML/Graphics/View.hpp @@ -140,6 +140,27 @@ public: //////////////////////////////////////////////////////////// void setViewport(const FloatRect& viewport); + //////////////////////////////////////////////////////////// + /// \brief Set the target scissor rectangle + /// + /// The scissor rectangle, expressed as a factor (between 0 and 1) of + /// the RenderTarget, specifies the region of the RenderTarget whose + /// pixels are able to be modified by draw or clear operations. + /// Any pixels which lie outside of the scissor rectangle will + /// not be modified by draw or clear operations. + /// For example, a scissor rectangle which only allows modifications + /// to the right side of the target would be defined + /// with View.setScissor(sf::FloatRect(0.5, 0, 0.5, 1)). + /// By default, a view has a scissor rectangle which allows + /// modifications to the entire target. + /// + /// \param scissor New scissor rectangle + /// + /// \see getScissor + /// + //////////////////////////////////////////////////////////// + void setScissor(const FloatRect& scissor); + //////////////////////////////////////////////////////////// /// \brief Reset the view to the given rectangle /// @@ -192,6 +213,16 @@ public: //////////////////////////////////////////////////////////// const FloatRect& getViewport() const; + //////////////////////////////////////////////////////////// + /// \brief Get the scissor rectangle of the view + /// + /// \return Scissor rectangle, expressed as a factor of the target size + /// + /// \see setScissor + /// + //////////////////////////////////////////////////////////// + const FloatRect& getScissor() const; + //////////////////////////////////////////////////////////// /// \brief Move the view relatively to its current position /// @@ -273,6 +304,7 @@ private: Vector2f m_size; ///< Size of the view, in scene coordinates float m_rotation; ///< Angle of rotation of the view rectangle, in degrees FloatRect m_viewport; ///< Viewport rectangle, expressed as a factor of the render-target's size + FloatRect m_scissor; ///< Scissor rectangle, expressed as a factor of the render-target's size mutable Transform m_transform; ///< Precomputed projection transform corresponding to the view mutable Transform m_inverseTransform; ///< Precomputed inverse projection transform corresponding to the view mutable bool m_transformUpdated; ///< Internal state telling if the transform needs to be updated @@ -305,6 +337,12 @@ private: /// rectangle doesn't have the same size as the viewport, its /// contents will be stretched to fit in. /// +/// The scissor rectangle allows for specifying regions of the +/// render target to which modifications can be made by draw +/// and clear operations. Only pixels that are within the region +/// will be able to be modified. Pixels outside of the region will +/// not be modified by draw or clear operations. +/// /// To apply a view, you have to assign it to the render target. /// Then, objects drawn in this render target will be /// affected by the view until you use another view. diff --git a/src/SFML/Graphics/RenderTarget.cpp b/src/SFML/Graphics/RenderTarget.cpp index 59e9e202..80d22c54 100644 --- a/src/SFML/Graphics/RenderTarget.cpp +++ b/src/SFML/Graphics/RenderTarget.cpp @@ -149,6 +149,10 @@ void RenderTarget::clear(const Color& color) // Unbind texture to fix RenderTexture preventing clear applyTexture(NULL); + // Apply the view (scissor testing can affect clearing) + if (!m_cache.enable || m_cache.viewChanged) + applyCurrentView(); + glCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f)); glCheck(glClear(GL_COLOR_BUFFER_BIT)); } @@ -191,6 +195,20 @@ IntRect RenderTarget::getViewport(const View& view) const } +//////////////////////////////////////////////////////////// +IntRect RenderTarget::getScissor(const View& view) const +{ + float width = static_cast(getSize().x); + float height = static_cast(getSize().y); + const FloatRect& scissor = view.getScissor(); + + return IntRect(static_cast(0.5f + width * scissor.left), + static_cast(0.5f + height * scissor.top), + static_cast(0.5f + width * scissor.width), + static_cast(0.5f + height * scissor.height)); +} + + //////////////////////////////////////////////////////////// Vector2f RenderTarget::mapPixelToCoords(const Vector2i& point) const { @@ -508,6 +526,7 @@ void RenderTarget::resetGLStates() glCheck(glDisable(GL_LIGHTING)); glCheck(glDisable(GL_DEPTH_TEST)); glCheck(glDisable(GL_ALPHA_TEST)); + glCheck(glDisable(GL_SCISSOR_TEST)); glCheck(glEnable(GL_TEXTURE_2D)); glCheck(glEnable(GL_BLEND)); glCheck(glMatrixMode(GL_MODELVIEW)); @@ -515,6 +534,7 @@ void RenderTarget::resetGLStates() glCheck(glEnableClientState(GL_VERTEX_ARRAY)); glCheck(glEnableClientState(GL_COLOR_ARRAY)); glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + m_cache.scissorEnabled = false; m_cache.glStatesSet = true; // Apply the default SFML states @@ -562,6 +582,45 @@ void RenderTarget::applyCurrentView() int top = getSize().y - (viewport.top + viewport.height); glCheck(glViewport(viewport.left, top, viewport.width, viewport.height)); + FloatRect scissor = m_view.getScissor(); + + if (m_cache.scissorEnabled) + { + if ((scissor.left != 0) || + (scissor.top != 0) || + (scissor.width != 1) || + (scissor.height != 1)) + { + // Set the scissor rectangle + IntRect pixelScissor = getScissor(m_view); + top = getSize().y - (pixelScissor.top + pixelScissor.height); + glCheck(glScissor(pixelScissor.left, top, pixelScissor.width, pixelScissor.height)); + } + else + { + glCheck(glDisable(GL_SCISSOR_TEST)); + + m_cache.scissorEnabled = false; + } + } + else + { + if ((scissor.left != 0) || + (scissor.top != 0) || + (scissor.width != 1) || + (scissor.height != 1)) + { + // Set the scissor rectangle + IntRect pixelScissor = getScissor(m_view); + top = getSize().y - (pixelScissor.top + pixelScissor.height); + glCheck(glScissor(pixelScissor.left, top, pixelScissor.width, pixelScissor.height)); + + glCheck(glEnable(GL_SCISSOR_TEST)); + + m_cache.scissorEnabled = true; + } + } + // Set the projection matrix glCheck(glMatrixMode(GL_PROJECTION)); glCheck(glLoadMatrixf(m_view.getTransform().getMatrix())); diff --git a/src/SFML/Graphics/View.cpp b/src/SFML/Graphics/View.cpp index 0fcf6548..7a0d9586 100644 --- a/src/SFML/Graphics/View.cpp +++ b/src/SFML/Graphics/View.cpp @@ -37,6 +37,7 @@ m_center (), m_size (), m_rotation (0), m_viewport (0, 0, 1, 1), +m_scissor (0, 0, 1, 1), m_transformUpdated (false), m_invTransformUpdated(false) { @@ -50,6 +51,7 @@ m_center (), m_size (), m_rotation (0), m_viewport (0, 0, 1, 1), +m_scissor (0, 0, 1, 1), m_transformUpdated (false), m_invTransformUpdated(false) { @@ -63,6 +65,7 @@ m_center (center), m_size (size), m_rotation (0), m_viewport (0, 0, 1, 1), +m_scissor (0, 0, 1, 1), m_transformUpdated (false), m_invTransformUpdated(false) { @@ -124,6 +127,13 @@ void View::setViewport(const FloatRect& viewport) } +//////////////////////////////////////////////////////////// +void View::setScissor(const FloatRect& scissor) +{ + m_scissor = scissor; +} + + //////////////////////////////////////////////////////////// void View::reset(const FloatRect& rectangle) { @@ -166,6 +176,13 @@ const FloatRect& View::getViewport() const } +//////////////////////////////////////////////////////////// +const FloatRect& View::getScissor() const +{ + return m_scissor; +} + + //////////////////////////////////////////////////////////// void View::move(float offsetX, float offsetY) {