607 lines
24 KiB
C++
607 lines
24 KiB
C++
////////////////////////////////////////////////////////////
|
|
//
|
|
// SFML - Simple and Fast Multimedia Library
|
|
// Copyright (C) 2007-2025 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
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Headers
|
|
////////////////////////////////////////////////////////////
|
|
#include <SFML/Graphics/Export.hpp>
|
|
|
|
#include <SFML/Graphics/BlendMode.hpp>
|
|
#include <SFML/Graphics/Color.hpp>
|
|
#include <SFML/Graphics/CoordinateType.hpp>
|
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
|
#include <SFML/Graphics/Rect.hpp>
|
|
#include <SFML/Graphics/RenderStates.hpp>
|
|
#include <SFML/Graphics/StencilMode.hpp>
|
|
#include <SFML/Graphics/Vertex.hpp>
|
|
#include <SFML/Graphics/View.hpp>
|
|
|
|
#include <SFML/System/Vector2.hpp>
|
|
|
|
#include <array>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
|
|
|
|
namespace sf
|
|
{
|
|
class Drawable;
|
|
class Shader;
|
|
class Texture;
|
|
class Transform;
|
|
class VertexBuffer;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Base class for all render targets (window, texture, ...)
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
class SFML_GRAPHICS_API RenderTarget
|
|
{
|
|
public:
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Destructor
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
virtual ~RenderTarget() = default;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Deleted copy constructor
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
RenderTarget(const RenderTarget&) = delete;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Deleted copy assignment
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
RenderTarget& operator=(const RenderTarget&) = delete;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Move constructor
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
RenderTarget(RenderTarget&&) noexcept = default;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Move assignment
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
RenderTarget& operator=(RenderTarget&&) noexcept = default;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Clear the entire target with a single color
|
|
///
|
|
/// This function is usually called once every frame,
|
|
/// to clear the previous contents of the target.
|
|
///
|
|
/// \param color Fill color to use to clear the render target
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void clear(Color color = Color::Black);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Clear the stencil buffer to a specific value
|
|
///
|
|
/// The specified value is truncated to the bit width of
|
|
/// the current stencil buffer.
|
|
///
|
|
/// \param stencilValue Stencil value to clear to
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void clearStencil(StencilValue stencilValue);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Clear the entire target with a single color and stencil value
|
|
///
|
|
/// The specified stencil value is truncated to the bit
|
|
/// width of the current stencil buffer.
|
|
///
|
|
/// \param color Fill color to use to clear the render target
|
|
/// \param stencilValue Stencil value to clear to
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void clear(Color color, StencilValue stencilValue);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \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 set.
|
|
/// The render target keeps its own copy of the view object,
|
|
/// so it is not necessary to keep the original one alive
|
|
/// after calling this function.
|
|
/// To restore the original view of the target, you can pass
|
|
/// the result of `getDefaultView()` to this function.
|
|
///
|
|
/// \param view New view to use
|
|
///
|
|
/// \see `getView`, `getDefaultView`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void setView(const View& view);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Get the view currently in use in the render target
|
|
///
|
|
/// \return The view object that is currently used
|
|
///
|
|
/// \see `setView`, `getDefaultView`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] const View& getView() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Get the default view of the render target
|
|
///
|
|
/// The default view has the initial size of the render target,
|
|
/// and never changes after the target has been created.
|
|
///
|
|
/// \return The default view of the render target
|
|
///
|
|
/// \see `setView`, `getView`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] const View& getDefaultView() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Get the viewport of a view, applied to this render target
|
|
///
|
|
/// The viewport 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 viewport
|
|
/// actually covers in the target.
|
|
///
|
|
/// \param view The view for which we want to compute the viewport
|
|
///
|
|
/// \return Viewport rectangle, expressed in pixels
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] 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
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] IntRect getScissor(const View& view) const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Convert a point from target coordinates to world
|
|
/// coordinates, using the current view
|
|
///
|
|
/// This function is an overload of the mapPixelToCoords
|
|
/// function that implicitly uses the current view.
|
|
/// It is equivalent to:
|
|
/// \code
|
|
/// target.mapPixelToCoords(point, target.getView());
|
|
/// \endcode
|
|
///
|
|
/// \param point Pixel to convert
|
|
///
|
|
/// \return The converted point, in "world" coordinates
|
|
///
|
|
/// \see `mapCoordsToPixel`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] Vector2f mapPixelToCoords(Vector2i point) const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Convert a point from target coordinates to world coordinates
|
|
///
|
|
/// This function finds the 2D position that matches the
|
|
/// given pixel of the render target. In other words, it does
|
|
/// the inverse of what the graphics card does, to find the
|
|
/// initial position of a rendered pixel.
|
|
///
|
|
/// Initially, both coordinate systems (world units and target pixels)
|
|
/// match perfectly. But if you define a custom view or resize your
|
|
/// render target, this assertion is not `true` anymore, i.e. a point
|
|
/// located at (10, 50) in your render target may map to the point
|
|
/// (150, 75) in your 2D world -- if the view is translated by (140, 25).
|
|
///
|
|
/// For render-windows, this function is typically used to find
|
|
/// which point (or object) is located below the mouse cursor.
|
|
///
|
|
/// This version uses a custom view for calculations, see the other
|
|
/// overload of the function if you want to use the current view of the
|
|
/// render target.
|
|
///
|
|
/// \param point Pixel to convert
|
|
/// \param view The view to use for converting the point
|
|
///
|
|
/// \return The converted point, in "world" units
|
|
///
|
|
/// \see `mapCoordsToPixel`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] Vector2f mapPixelToCoords(Vector2i point, const View& view) const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Convert a point from world coordinates to target
|
|
/// coordinates, using the current view
|
|
///
|
|
/// This function is an overload of the `mapCoordsToPixel`
|
|
/// function that implicitly uses the current view.
|
|
/// It is equivalent to:
|
|
/// \code
|
|
/// target.mapCoordsToPixel(point, target.getView());
|
|
/// \endcode
|
|
///
|
|
/// \param point Point to convert
|
|
///
|
|
/// \return The converted point, in target coordinates (pixels)
|
|
///
|
|
/// \see `mapPixelToCoords`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] Vector2i mapCoordsToPixel(Vector2f point) const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Convert a point from world coordinates to target coordinates
|
|
///
|
|
/// This function finds the pixel of the render target that matches
|
|
/// the given 2D point. In other words, it goes through the same process
|
|
/// as the graphics card, to compute the final position of a rendered point.
|
|
///
|
|
/// Initially, both coordinate systems (world units and target pixels)
|
|
/// match perfectly. But if you define a custom view or resize your
|
|
/// render target, this assertion is not `true` anymore, i.e. a point
|
|
/// located at (150, 75) in your 2D world may map to the pixel
|
|
/// (10, 50) of your render target -- if the view is translated by (140, 25).
|
|
///
|
|
/// This version uses a custom view for calculations, see the other
|
|
/// overload of the function if you want to use the current view of the
|
|
/// render target.
|
|
///
|
|
/// \param point Point to convert
|
|
/// \param view The view to use for converting the point
|
|
///
|
|
/// \return The converted point, in target coordinates (pixels)
|
|
///
|
|
/// \see `mapPixelToCoords`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] Vector2i mapCoordsToPixel(Vector2f point, 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 vertexCount 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,
|
|
std::size_t vertexCount,
|
|
PrimitiveType type,
|
|
const RenderStates& states = RenderStates::Default);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Draw primitives defined by a vertex buffer
|
|
///
|
|
/// \param vertexBuffer Vertex buffer
|
|
/// \param states Render states to use for drawing
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void draw(const VertexBuffer& vertexBuffer, const RenderStates& states = RenderStates::Default);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Draw primitives defined by a vertex buffer
|
|
///
|
|
/// \param vertexBuffer Vertex buffer
|
|
/// \param firstVertex Index of the first vertex to render
|
|
/// \param vertexCount Number of vertices to render
|
|
/// \param states Render states to use for drawing
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void draw(const VertexBuffer& vertexBuffer,
|
|
std::size_t firstVertex,
|
|
std::size_t vertexCount,
|
|
const RenderStates& states = RenderStates::Default);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Return the size of the rendering region of the target
|
|
///
|
|
/// \return Size in pixels
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] virtual Vector2u getSize() const = 0;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Tell if the render target will use sRGB encoding when drawing on it
|
|
///
|
|
/// \return `true` if the render target use sRGB encoding, `false` otherwise
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] virtual bool isSrgb() const;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Activate or deactivate the render target for rendering
|
|
///
|
|
/// This function makes the render target's context current for
|
|
/// future OpenGL rendering operations (so you shouldn't care
|
|
/// about it if you're not doing direct OpenGL stuff).
|
|
/// A render target's context is active only on the current thread,
|
|
/// if you want to make it active on another thread you have
|
|
/// to deactivate it on the previous thread first if it was active.
|
|
/// Only one context can be current in a thread, so if you
|
|
/// want to draw OpenGL geometry to another render target
|
|
/// don't forget to activate it again. Activating a render
|
|
/// target will automatically deactivate the previously active
|
|
/// context (if any).
|
|
///
|
|
/// \param active `true` to activate, `false` to deactivate
|
|
///
|
|
/// \return `true` if operation was successful, `false` otherwise
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
[[nodiscard]] virtual bool setActive(bool active = true);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \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 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
|
|
///
|
|
/// More specifically, it must be used around code that
|
|
/// calls `draw` functions. Example:
|
|
/// \code
|
|
/// // OpenGL code here...
|
|
/// window.pushGLStates();
|
|
/// window.draw(...);
|
|
/// window.draw(...);
|
|
/// window.popGLStates();
|
|
/// // OpenGL code here...
|
|
/// \endcode
|
|
///
|
|
/// 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 `popGLStates`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void pushGLStates();
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Restore the previously saved OpenGL render states and matrices
|
|
///
|
|
/// See the description of `pushGLStates` to get a detailed
|
|
/// description of these functions.
|
|
///
|
|
/// \see `pushGLStates`
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
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:
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Default constructor
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
RenderTarget() = default;
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Performs the common initialization step after creation
|
|
///
|
|
/// The derived classes must call this function after the
|
|
/// target is created and ready for drawing.
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void initialize();
|
|
|
|
private:
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply the current view
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyCurrentView();
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply a new blending mode
|
|
///
|
|
/// \param mode Blending mode to apply
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyBlendMode(const BlendMode& mode);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply a new stencil mode
|
|
///
|
|
/// \param mode Stencil mode to apply
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyStencilMode(const StencilMode& mode);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply a new transform
|
|
///
|
|
/// \param transform Transform to apply
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyTransform(const Transform& transform);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply a new texture
|
|
///
|
|
/// \param texture Texture to apply
|
|
/// \param coordinateType The texture coordinate type to use
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyTexture(const Texture* texture, CoordinateType coordinateType = CoordinateType::Pixels);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Apply a new shader
|
|
///
|
|
/// \param shader Shader to apply
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void applyShader(const Shader* shader);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Setup environment for drawing
|
|
///
|
|
/// \param useVertexCache Are we going to use the vertex cache?
|
|
/// \param states Render states to use for drawing
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void setupDraw(bool useVertexCache, const RenderStates& states);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Draw the primitives
|
|
///
|
|
/// \param type Type of primitives to draw
|
|
/// \param firstVertex Index of the first vertex to use when drawing
|
|
/// \param vertexCount Number of vertices to use when drawing
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Clean up environment after drawing
|
|
///
|
|
/// \param states Render states used for drawing
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
void cleanupDraw(const RenderStates& states);
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \brief Render states cache
|
|
///
|
|
////////////////////////////////////////////////////////////
|
|
struct StatesCache
|
|
{
|
|
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?
|
|
bool stencilEnabled{}; //!< Is stencil testing enabled?
|
|
BlendMode lastBlendMode; //!< Cached blending mode
|
|
StencilMode lastStencilMode; //!< Cached stencil
|
|
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<Vertex, 4> vertexCache{}; //!< Pre-transformed vertices cache
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Member data
|
|
////////////////////////////////////////////////////////////
|
|
View m_defaultView; //!< Default view
|
|
View m_view; //!< Current view
|
|
StatesCache m_cache{}; //!< Render states cache
|
|
std::uint64_t m_id{}; //!< Unique number that identifies the RenderTarget
|
|
};
|
|
|
|
} // namespace sf
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// \class sf::RenderTarget
|
|
/// \ingroup graphics
|
|
///
|
|
/// `sf::RenderTarget` defines the common behavior of all the
|
|
/// 2D render targets usable in the graphics module. It makes
|
|
/// it possible to draw 2D entities like sprites, shapes, text
|
|
/// without using any OpenGL command directly.
|
|
///
|
|
/// A `sf::RenderTarget` is also able to use views (`sf::View`),
|
|
/// which are a kind of 2D cameras. With views you can globally
|
|
/// scroll, rotate or zoom everything that is drawn,
|
|
/// without having to transform every single entity. See the
|
|
/// documentation of `sf::View` for more details and sample pieces of
|
|
/// code about this class.
|
|
///
|
|
/// 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
|
|
/// `pushGLStates`/`popGLStates` functions.
|
|
///
|
|
/// While render targets are moveable, it is not valid to move them
|
|
/// between threads. This will cause your program to crash. The
|
|
/// problem boils down to OpenGL being limited with regard to how it
|
|
/// works in multithreaded environments. Please ensure you only move
|
|
/// render targets within the same thread.
|
|
///
|
|
/// \see `sf::RenderWindow`, `sf::RenderTexture`, `sf::View`
|
|
///
|
|
////////////////////////////////////////////////////////////
|