mirror of
https://github.com/SFML/SFML.git
synced 2024-11-24 20:31:05 +08:00
Added support for stencil testing.
Co-authored-by: binary1248 <binary1248@hotmail.com> Co-authored-by: Chris Thrasher <chrisjthrasher@gmail.com>
This commit is contained in:
parent
9022d9564d
commit
eb07e1e6c5
@ -20,6 +20,7 @@ endif()
|
||||
|
||||
if(SFML_BUILD_GRAPHICS)
|
||||
add_subdirectory(opengl)
|
||||
add_subdirectory(stencil)
|
||||
|
||||
if(NOT SFML_OS_IOS)
|
||||
add_subdirectory(joystick)
|
||||
|
7
examples/stencil/CMakeLists.txt
Normal file
7
examples/stencil/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# all source files
|
||||
set(SRC Stencil.cpp)
|
||||
|
||||
# define the stencil target
|
||||
sfml_add_example(stencil GUI_APP
|
||||
SOURCES ${SRC}
|
||||
DEPENDS SFML::Graphics)
|
138
examples/stencil/Stencil.cpp
Normal file
138
examples/stencil/Stencil.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics.hpp>
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Entry point of application
|
||||
///
|
||||
/// \return Application exit code
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
int main()
|
||||
{
|
||||
// Create the window of the application with a stencil buffer
|
||||
sf::RenderWindow window(sf::VideoMode({600, 600}),
|
||||
"SFML Stencil",
|
||||
sf::Style::Titlebar | sf::Style::Close,
|
||||
sf::State::Windowed,
|
||||
sf::ContextSettings(0, 8));
|
||||
window.setVerticalSyncEnabled(true);
|
||||
|
||||
sf::RectangleShape red({500, 50});
|
||||
red.setFillColor(sf::Color::Red);
|
||||
red.setPosition({270, 70});
|
||||
red.setRotation(sf::degrees(60));
|
||||
|
||||
sf::RectangleShape green({500, 50});
|
||||
green.setFillColor(sf::Color::Green);
|
||||
green.setPosition({370, 100});
|
||||
green.setRotation(sf::degrees(120));
|
||||
|
||||
sf::RectangleShape blue({500, 50});
|
||||
blue.setFillColor(sf::Color::Blue);
|
||||
blue.setPosition({550, 470});
|
||||
blue.setRotation(sf::degrees(180));
|
||||
|
||||
while (window.isOpen())
|
||||
{
|
||||
// Handle events
|
||||
for (sf::Event event; window.pollEvent(event);)
|
||||
{
|
||||
// Window closed: exit
|
||||
if (event.type == sf::Event::Closed)
|
||||
{
|
||||
window.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// When drawing using a 2D API, we normally resort to what is known as the "painter's algorithm".
|
||||
// Because our graphics primitives lack any depth information, objects that are drawn later in the frame will
|
||||
// overlap objects drawn earlier in the frame. This means that the objects have to be sorted from farthest to
|
||||
// closest and drawn in that order to appear correct.
|
||||
// This also means that objects cannot simultaneously be both "in front" and "behind" already drawn objects.
|
||||
|
||||
// With the magic of the stencil buffer we can get around this rule. Much like the depth buffer in 3D applications
|
||||
// the stencil buffer holds additional information that informs the rendering pipeline about our intentions.
|
||||
// Unlike the depth buffer which requires that all drawn primitives contain depth information (e.g. in the form
|
||||
// of 3D vertices), the stencil buffer allows us to specify stencil values for whole primitives ourselves.
|
||||
|
||||
// For every fragment/pixel that would be written to the screen, after the fragment shader is executed, the stencil
|
||||
// test is performed. First, the rendering pipeline will ask whether the pixel in question should even be kept or
|
||||
// discarded. This is known as the stencil test. In order to answer this question 2 integer values are compared
|
||||
// against each other, the value already in the screen stencil buffer corresponding to the pixel in question and
|
||||
// the new value of the incoming pixel to perform the test for. The value of the incoming pixel is known as the
|
||||
// reference value and can be set per draw operation when using the sfml-graphics drawing API. All mathematical
|
||||
// operations comparing 2 integers are supported: Less, LessEqual, Greater, GreaterEqual, Equal, NotEqual.
|
||||
// Additionally, 2 special comparisons are provided: Always and Never. Always will make sure the stencil test
|
||||
// will always pass, whereas Never will make sure the stencil test never passes. The incoming reference value
|
||||
// is compared to the stencil buffer value in the following order: (ReferenceValue Comparison BufferValue)
|
||||
// If the test evaluates to true, the pixel is kept, otherwise it is culled and will no longer contribute to
|
||||
// the frame in any way.
|
||||
|
||||
// Once the stencil test passes, the value in the stencil buffer can be updated with a new value. The new value
|
||||
// is determined by the update operation and for the Replace operation the incoming reference value as well.
|
||||
// In the case of Increment, Decrement and Invert, the existing value in the stencil buffer is modified accordingly,
|
||||
// Invert will perform a bit-wise inversion of the integer value in the buffer. Keep will not modify the value
|
||||
// in the buffer whereas Zero will set it to 0. Replace will replace the value in the buffer with the incoming
|
||||
// reference value.
|
||||
|
||||
// Like all data types, the stencil values in the stencil buffer have a finite bit width. Typically stencil buffers
|
||||
// with 8-bits are offered by the graphics implementation. In complex scenarios, we might want to partition our
|
||||
// bits up into multiple areas so a single stencil buffer value can be used for multiple purposes simultaneously.
|
||||
// For this purpose, we can specify a mask value that is bit-wise ANDed with both the incoming reference value
|
||||
// and the stencil buffer value before they are compared. For simple cases, a mask of ~0 (all 1s) can be used which
|
||||
// is the equivalent of disabling masking all together.
|
||||
|
||||
// For certain effects, objects might have to be rendered multiple times. Once to establish the stencil value of
|
||||
// that object within the stencil buffer and another to draw the object itself including its texture/color. Drawing
|
||||
// objects with the sole purpose of updating stencil buffer values is also known as performing a stencil-only pass.
|
||||
// Skipping texturing and writes to the color buffer can save a lot of time depending on the object to be drawn.
|
||||
// StencilMode allows us to perform stencil-only drawing by setting the corresponding flag to true.
|
||||
|
||||
// In this example, we demonstrate how can can draw 3 cyclically overlapping rectangles using the stencil buffer.
|
||||
// Without the stencil buffer, 1 of the rectangles would have to be precisely split along the edge of another
|
||||
// rectangle and both pieces would have to be drawn at different stages in the draw pass. This would not only be
|
||||
// almost impossible to compute to the required accuracy to mimic the GPU's vertex computations but splitting a
|
||||
// primitive up and drawing the pieces in seperate draw calls would introduce noticeable artifacts which would
|
||||
// reduce the overall quality of the output image.
|
||||
|
||||
// To start with, we initialize the stencil buffer values for every pixel to 0 at the start of each frame. In
|
||||
// our draw calls we need to make sure that the stencil reference values of all objects will pass the test compared
|
||||
// to the initial buffer value. In the case of Always, the initial value is insignificant, when we use Greater we
|
||||
// make sure the reference value of 2 is greater than 0.
|
||||
|
||||
// Clear the window color to black and the initial stencil buffer values to 0
|
||||
window.clear(sf::Color::Black, 0);
|
||||
|
||||
// Draw rectangles
|
||||
|
||||
// We draw the first rectangle with comparison set to always so that it will definitely draw and update (Replace)
|
||||
// the stencil buffer values of its pixels to the specified reference value.
|
||||
window.draw(red,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Replace, 3, ~0u, false});
|
||||
|
||||
// Just like the first, we draw the second rectangle with comparison set to always so that it will definitely
|
||||
// draw and update (Replace) the stencil buffer values of its pixels to the specified reference value.
|
||||
// In the case of pixels overlapping the first rectangle, because we specify Always as the comparison, it is
|
||||
// as if we are drawing using the painter's algorithm, i.e. newer pixels overwrite older pixels.
|
||||
window.draw(green,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Replace, 1, ~0u, false});
|
||||
|
||||
// Now comes the magic. We want to draw the third rectangle so it is behind i.e. does not overwrite pixels of the
|
||||
// first rectangle but in front of i.e. overwrites pixels of the second rectangle. We already set the reference
|
||||
// value of the first rectangle to 3 and the second rectangle to 1, so in order to be "between" them, this rectangle
|
||||
// has to have a reference value of 2. 2 is not greather than 3 so pixels of this rectangle will not overwrite pixels
|
||||
// of the first rectangle, however 2 is greater than 1 and thus pixels of this rectangle will overwrite pixels of the
|
||||
// second rectangle. The stencil update operation for this draw operation is not significant in any way since this is
|
||||
// the last draw call in the frame.
|
||||
window.draw(blue,
|
||||
sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Replace, 2, ~0u, false});
|
||||
|
||||
// Display things on screen
|
||||
window.display();
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -7,7 +7,7 @@ if(SFML_OS_IOS)
|
||||
set_source_files_properties(${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif()
|
||||
|
||||
# define the pong target
|
||||
# define the tennis target
|
||||
sfml_add_example(tennis GUI_APP
|
||||
SOURCES ${SRC}
|
||||
BUNDLE_RESOURCES ${RESOURCES}
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Shape.hpp>
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Transform.hpp>
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include <SFML/Graphics/BlendMode.hpp>
|
||||
#include <SFML/Graphics/CoordinateType.hpp>
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
#include <SFML/Graphics/Transform.hpp>
|
||||
|
||||
|
||||
@ -52,6 +53,7 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
/// to using sf::RenderStates::Default.
|
||||
/// The default set defines:
|
||||
/// \li the BlendAlpha blend mode
|
||||
/// \li the default StencilMode (no stencil)
|
||||
/// \li the identity transform
|
||||
/// \li a null texture
|
||||
/// \li a null shader
|
||||
@ -67,6 +69,14 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates(const BlendMode& theBlendMode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct a default set of render states with a custom stencil mode
|
||||
///
|
||||
/// \param theStencilMode Stencil mode to use
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates(const StencilMode& theStencilMode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct a default set of render states with a custom transform
|
||||
///
|
||||
@ -95,6 +105,7 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
/// \brief Construct a set of render states with all its attributes
|
||||
///
|
||||
/// \param theBlendMode Blend mode to use
|
||||
/// \param theStencilMode Stencil mode to use
|
||||
/// \param theTransform Transform to use
|
||||
/// \param theCoordinateType Texture coordinate type to use
|
||||
/// \param theTexture Texture to use
|
||||
@ -102,6 +113,7 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates(const BlendMode& theBlendMode,
|
||||
const StencilMode& theStencilMode,
|
||||
const Transform& theTransform,
|
||||
CoordinateType theCoordinateType,
|
||||
const Texture* theTexture,
|
||||
@ -117,6 +129,7 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
BlendMode blendMode{BlendAlpha}; //!< Blending mode
|
||||
StencilMode stencilMode; //!< Stencil mode
|
||||
Transform transform; //!< Transform
|
||||
CoordinateType coordinateType{CoordinateType::Pixels}; //!< Texture coordinate type
|
||||
const Texture* texture{}; //!< Texture
|
||||
@ -130,9 +143,10 @@ struct SFML_GRAPHICS_API RenderStates
|
||||
/// \class sf::RenderStates
|
||||
/// \ingroup graphics
|
||||
///
|
||||
/// There are five global states that can be applied to
|
||||
/// There are six 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 stencil mode: how pixels of the object interact with the stencil buffer
|
||||
/// \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
|
||||
|
@ -35,6 +35,7 @@
|
||||
#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>
|
||||
|
||||
@ -97,6 +98,29 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
void clear(const 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 value 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 value Stencil value to clear to
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void clear(const Color& color, StencilValue stencilValue);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current active view
|
||||
///
|
||||
@ -452,6 +476,14 @@ private:
|
||||
////////////////////////////////////////////////////////////
|
||||
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
|
||||
///
|
||||
@ -514,7 +546,9 @@ private:
|
||||
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?
|
||||
|
256
include/SFML/Graphics/StencilMode.hpp
Normal file
256
include/SFML/Graphics/StencilMode.hpp
Normal file
@ -0,0 +1,256 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/// \brief Enumeration of the stencil test comparisons that can be performed
|
||||
///
|
||||
/// The comparisons are mapped directly to their OpenGL equivalents,
|
||||
/// specified by glStencilFunc().
|
||||
////////////////////////////////////////////////////////
|
||||
enum class StencilComparison
|
||||
{
|
||||
Never, //!< The stencil test never passes
|
||||
Less, //!< The stencil test passes if the new value is less than the value in the stencil buffer
|
||||
LessEqual, //!< The stencil test passes if the new value is less than or equal to the value in the stencil buffer
|
||||
Greater, //!< The stencil test passes if the new value is greater than the value in the stencil buffer
|
||||
GreaterEqual, //!< The stencil test passes if the new value is greater than or equal to the value in the stencil buffer
|
||||
Equal, //!< The stencil test passes if the new value is strictly equal to the value in the stencil buffer
|
||||
NotEqual, //!< The stencil test passes if the new value is strictly inequal to the value in the stencil buffer
|
||||
Always //!< The stencil test always passes
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/// \brief Enumeration of the stencil buffer update operations
|
||||
///
|
||||
/// The update operations are mapped directly to their OpenGL equivalents,
|
||||
/// specified by glStencilOp().
|
||||
////////////////////////////////////////////////////////
|
||||
enum class StencilUpdateOperation
|
||||
{
|
||||
Keep, //!< If the stencil test passes, the value in the stencil buffer is not modified
|
||||
Zero, //!< If the stencil test passes, the value in the stencil buffer is set to zero
|
||||
Replace, //!< If the stencil test passes, the value in the stencil buffer is set to the new value
|
||||
Increment, //!< If the stencil test passes, the value in the stencil buffer is incremented and if required clamped
|
||||
Decrement, //!< If the stencil test passes, the value in the stencil buffer is decremented and if required clamped
|
||||
Invert, //!< If the stencil test passes, the value in the stencil buffer is bitwise inverted
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
/// \brief Stencil value type (also used as a mask)
|
||||
///
|
||||
////////////////////////////////////////////////////////
|
||||
struct SFML_GRAPHICS_API StencilValue
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct a stencil value from a signed integer
|
||||
///
|
||||
/// \param theValue Signed integer value to use
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
StencilValue(int theValue);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct a stencil value from an unsigned integer
|
||||
///
|
||||
/// \param theValue Unsigned integer value to use
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
StencilValue(unsigned int theValue);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Disable construction from any other type
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
StencilValue(T) = delete;
|
||||
|
||||
unsigned int value = 0u; //!< The stored stencil value
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Stencil modes for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct SFML_GRAPHICS_API StencilMode
|
||||
{
|
||||
StencilComparison stencilComparison{StencilComparison::Always}; //!< The comparison we're performing the stencil test with
|
||||
StencilUpdateOperation stencilUpdateOperation{
|
||||
StencilUpdateOperation::Keep}; //!< The update operation to perform if the stencil test passes
|
||||
StencilValue stencilReference{0}; //!< The reference value we're performing the stencil test with
|
||||
StencilValue stencilMask{~0u}; //!< The mask to apply to both the reference value and the value in the stencil buffer
|
||||
bool stencilOnly{}; //!< Whether we should update the color buffer in addition to the stencil buffer
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates StencilMode
|
||||
/// \brief Overload of the == operator
|
||||
///
|
||||
/// \param left Left operand
|
||||
/// \param right Right operand
|
||||
///
|
||||
/// \return True if stencil modes are equal, false if they are different
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
SFML_GRAPHICS_API bool operator==(const StencilMode& left, const StencilMode& right);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \relates StencilMode
|
||||
/// \brief Overload of the != operator
|
||||
///
|
||||
/// \param left Left operand
|
||||
/// \param right Right operand
|
||||
///
|
||||
/// \return True if stencil modes are different, false if they are equal
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
SFML_GRAPHICS_API bool operator!=(const StencilMode& left, const StencilMode& right);
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \class sf::StencilMode
|
||||
/// \ingroup graphics
|
||||
///
|
||||
/// sf::StencilMode is a class that controls stencil testing.
|
||||
///
|
||||
/// In addition to drawing to the visible portion of a render target,
|
||||
/// there is the possibility to "draw" to a so-called stencil buffer.
|
||||
/// The stencil buffer is a special non-visible buffer that can contain
|
||||
/// a single value per pixel that is drawn. This can be thought of as a
|
||||
/// fifth value in addition to red, green, blue and alpha values. The maximum
|
||||
/// value that can be represented depends on what is supported by the system.
|
||||
/// Typically support for a 8-bit stencil buffer should always be available.
|
||||
/// This will also have to be requested when creating a render target via
|
||||
/// the sf::ContextSettings that is passed during creation. Stencil testing
|
||||
/// will not work if there is no stencil buffer available in the target
|
||||
/// that is being drawn to.
|
||||
///
|
||||
/// Initially, just like with the visible color buffer, the stencil value of
|
||||
/// each pixel is set to an undefined value. Calling sf::RenderTarget::clear
|
||||
/// will set each pixel's stencil value to 0. sf::RenderTarget::clear can be
|
||||
/// called at any time to reset the stencil values back to 0.
|
||||
///
|
||||
/// When drawing an object, before each pixel of the color buffer is updated
|
||||
/// with its new color value, the stencil test is performed. During this test
|
||||
/// 2 values are compared with each other: the reference value that is passed
|
||||
/// via sf::StencilMode and the value that is currently in the stencil buffer.
|
||||
/// The arithmetic comparison that is performed on the 2 values can also be
|
||||
/// controlled via sf::StencilMode. Depending on whether the test passes i.e.
|
||||
/// the comparison yields true, the color buffer is updated with its new RGBA
|
||||
/// value and if set in sf::StencilMode the stencil buffer is updated
|
||||
/// accordingly. The new stencil value will be used during stencil testing the
|
||||
/// next time the pixel is drawn to.
|
||||
///
|
||||
/// The class is composed of 5 components, each of which has its
|
||||
/// own public member variable:
|
||||
/// \li Stencil Comparison (\ref stencilComparison)
|
||||
/// \li Stencil Update Operation (\ref stencilUpdateOperation)
|
||||
/// \li Stencil Reference Value (\ref stencilReference)
|
||||
/// \li Stencil Mask Value (\ref stencilMask)
|
||||
/// \li Stencil Only Update (\ref stencilOnly)
|
||||
///
|
||||
/// The stencil comparison specifies the comparison that is performed between
|
||||
/// the reference value of the currently active sf::StencilMode and the value
|
||||
/// that is currently in the stencil buffer. This comparison determines whether
|
||||
/// the stencil test passes or fails.
|
||||
///
|
||||
/// The stencil update operation specifies how the stencil buffer is updated if
|
||||
/// the stencil test passes. If the stencil test fails, neither the color or
|
||||
/// stencil buffers will be modified. If incrementing or decrementing the
|
||||
/// stencil value, the new value will be clamped to the range from 0 to the
|
||||
/// maximum representable value given the bit width of the stencil buffer
|
||||
/// e.g. 255 if an 8-bit stencil buffer is being used.
|
||||
///
|
||||
/// The reference value is used both during the comparison with the current
|
||||
/// stencil buffer value and as the new value to be written when the operation
|
||||
/// is set to Replace.
|
||||
///
|
||||
/// The mask value is used to mask the bits of both the reference value and
|
||||
/// the value in the stencil buffer during the comparison and when updating.
|
||||
/// The mask can be used to e.g. segment the stencil value bits into separate
|
||||
/// regions that are used for different purposes.
|
||||
///
|
||||
/// In certain situations, it might make sense to only write to the stencil
|
||||
/// buffer and not the color buffer during a draw. The written stencil buffer
|
||||
/// value can then be used in subsequent draws as a masking region.
|
||||
///
|
||||
/// In SFML, a stencil mode can be specified every time you draw a sf::Drawable
|
||||
/// object to a render target. It is part of the sf::RenderStates compound
|
||||
/// that is passed to the member function sf::RenderTarget::draw().
|
||||
///
|
||||
/// Usage example:
|
||||
/// \code
|
||||
/// // Make sure we create a RenderTarget with a stencil buffer by specifying it via the context settings
|
||||
/// sf::RenderWindow window(sf::VideoMode({250, 200}), "Stencil Window", sf::Style::Default, sf::ContextSettings(0, 8));
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// // Left circle
|
||||
/// sf::CircleShape left(100.f);
|
||||
/// left.setFillColor(sf::Color::Green);
|
||||
/// left.setPosition({0, 0});
|
||||
///
|
||||
/// // Middle circle
|
||||
/// sf::CircleShape middle(100.f);
|
||||
/// middle.setFillColor(sf::Color::Yellow);
|
||||
/// middle.setPosition({25, 0});
|
||||
///
|
||||
/// // Right circle
|
||||
/// sf::CircleShape right(100.f);
|
||||
/// right.setFillColor(sf::Color::Red);
|
||||
/// right.setPosition({50, 0});
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// // Clear the stencil buffer to 0 at the start of every frame
|
||||
/// window.clear(sf::Color::Black, 0);
|
||||
///
|
||||
/// ...
|
||||
///
|
||||
/// // Draw the middle circle in a stencil-only pass and write the value 1
|
||||
/// // to the stencil buffer for every pixel the circle would have affected
|
||||
/// window.draw(middle, sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Replace, 1, 0xFF, true});
|
||||
///
|
||||
/// // Draw the left and right circles
|
||||
/// // Only allow rendering to pixels whose stencil value is not
|
||||
/// // equal to 1 i.e. weren't written when drawing the middle circle
|
||||
/// window.draw(left, sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 1, 0xFF, false});
|
||||
/// window.draw(right, sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 1, 0xFF, false});
|
||||
/// \endcode
|
||||
///
|
||||
/// \see sf::RenderStates, sf::RenderTarget
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
@ -34,6 +34,8 @@ set(SRC
|
||||
${INCROOT}/RenderWindow.hpp
|
||||
${SRCROOT}/Shader.cpp
|
||||
${INCROOT}/Shader.hpp
|
||||
${SRCROOT}/StencilMode.cpp
|
||||
${INCROOT}/StencilMode.hpp
|
||||
${SRCROOT}/Texture.cpp
|
||||
${INCROOT}/Texture.hpp
|
||||
${SRCROOT}/TextureSaver.cpp
|
||||
|
@ -106,11 +106,13 @@
|
||||
#define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
|
||||
#define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_OES
|
||||
#define GLEXT_GL_DEPTH_COMPONENT GL_DEPTH_COMPONENT16_OES
|
||||
#define GLEXT_GL_STENCIL_INDEX8 GL_STENCIL_INDEX8
|
||||
#define GLEXT_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_OES
|
||||
#define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_OES
|
||||
#define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
|
||||
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES
|
||||
#define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_OES
|
||||
#define GLEXT_GL_STENCIL_ATTACHMENT GL_STENCIL_ATTACHMENT_OES
|
||||
|
||||
// Core since 3.0
|
||||
#define GLEXT_packed_depth_stencil SF_GLAD_GL_OES_packed_depth_stencil
|
||||
@ -277,6 +279,7 @@
|
||||
#define GLEXT_glGenerateMipmap glGenerateMipmapEXT
|
||||
#define GLEXT_GL_FRAMEBUFFER GL_FRAMEBUFFER_EXT
|
||||
#define GLEXT_GL_RENDERBUFFER GL_RENDERBUFFER_EXT
|
||||
#define GLEXT_GL_STENCIL_INDEX8 GL_STENCIL_INDEX8_EXT
|
||||
#define GLEXT_GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
|
||||
#define GLEXT_GL_DEPTH_ATTACHMENT GL_DEPTH_ATTACHMENT_EXT
|
||||
#define GLEXT_GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_EXT
|
||||
|
@ -56,6 +56,12 @@ RenderStates::RenderStates(const BlendMode& theBlendMode) : blendMode(theBlendMo
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const StencilMode& theStencilMode) : stencilMode(theStencilMode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const Texture* theTexture) : texture(theTexture)
|
||||
{
|
||||
@ -70,11 +76,13 @@ RenderStates::RenderStates(const Shader* theShader) : shader(theShader)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const BlendMode& theBlendMode,
|
||||
const StencilMode& theStencilMode,
|
||||
const Transform& theTransform,
|
||||
CoordinateType theCoordinateType,
|
||||
const Texture* theTexture,
|
||||
const Shader* theShader) :
|
||||
blendMode(theBlendMode),
|
||||
stencilMode(theStencilMode),
|
||||
transform(theTransform),
|
||||
coordinateType(theCoordinateType),
|
||||
texture(theTexture),
|
||||
|
@ -147,6 +147,50 @@ std::uint32_t equationToGlConstant(sf::BlendMode::Equation blendEquation)
|
||||
|
||||
return GLEXT_GL_FUNC_ADD;
|
||||
}
|
||||
|
||||
|
||||
// Convert an UpdateOperation constant to the corresponding OpenGL constant.
|
||||
std::uint32_t stencilOperationToGlConstant(sf::StencilUpdateOperation operation)
|
||||
{
|
||||
// clang-format off
|
||||
switch (operation)
|
||||
{
|
||||
case sf::StencilUpdateOperation::Keep: return GL_KEEP;
|
||||
case sf::StencilUpdateOperation::Zero: return GL_ZERO;
|
||||
case sf::StencilUpdateOperation::Replace: return GL_REPLACE;
|
||||
case sf::StencilUpdateOperation::Increment: return GL_INCR;
|
||||
case sf::StencilUpdateOperation::Decrement: return GL_DECR;
|
||||
case sf::StencilUpdateOperation::Invert: return GL_INVERT;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
sf::err() << "Invalid value for sf::StencilUpdateOperation! Fallback to sf::StencilMode::Keep." << std::endl;
|
||||
assert(false);
|
||||
return GL_KEEP;
|
||||
}
|
||||
|
||||
|
||||
// Convert a Comparison constant to the corresponding OpenGL constant.
|
||||
std::uint32_t stencilFunctionToGlConstant(sf::StencilComparison comparison)
|
||||
{
|
||||
// clang-format off
|
||||
switch (comparison)
|
||||
{
|
||||
case sf::StencilComparison::Never: return GL_NEVER;
|
||||
case sf::StencilComparison::Less: return GL_LESS;
|
||||
case sf::StencilComparison::LessEqual: return GL_LEQUAL;
|
||||
case sf::StencilComparison::Greater: return GL_GREATER;
|
||||
case sf::StencilComparison::GreaterEqual: return GL_GEQUAL;
|
||||
case sf::StencilComparison::Equal: return GL_EQUAL;
|
||||
case sf::StencilComparison::NotEqual: return GL_NOTEQUAL;
|
||||
case sf::StencilComparison::Always: return GL_ALWAYS;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
sf::err() << "Invalid value for sf::StencilComparison! Fallback to sf::StencilMode::Always." << std::endl;
|
||||
assert(false);
|
||||
return GL_ALWAYS;
|
||||
}
|
||||
} // namespace RenderTargetImpl
|
||||
} // namespace
|
||||
|
||||
@ -171,6 +215,43 @@ void RenderTarget::clear(const Color& color)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::clearStencil(StencilValue stencilValue)
|
||||
{
|
||||
if (RenderTargetImpl::isActive(m_id) || setActive(true))
|
||||
{
|
||||
// Unbind texture to fix RenderTexture preventing clear
|
||||
applyTexture(nullptr);
|
||||
|
||||
// Apply the view (scissor testing can affect clearing)
|
||||
if (!m_cache.enable || m_cache.viewChanged)
|
||||
applyCurrentView();
|
||||
|
||||
glCheck(glClearStencil(static_cast<int>(stencilValue.value)));
|
||||
glCheck(glClear(GL_STENCIL_BUFFER_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::clear(const Color& color, StencilValue stencilValue)
|
||||
{
|
||||
if (RenderTargetImpl::isActive(m_id) || setActive(true))
|
||||
{
|
||||
// Unbind texture to fix RenderTexture preventing clear
|
||||
applyTexture(nullptr);
|
||||
|
||||
// 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(glClearStencil(static_cast<int>(stencilValue.value)));
|
||||
glCheck(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::setView(const View& view)
|
||||
{
|
||||
@ -519,6 +600,7 @@ void RenderTarget::resetGLStates()
|
||||
// Define the default OpenGL states
|
||||
glCheck(glDisable(GL_CULL_FACE));
|
||||
glCheck(glDisable(GL_LIGHTING));
|
||||
glCheck(glDisable(GL_STENCIL_TEST));
|
||||
glCheck(glDisable(GL_DEPTH_TEST));
|
||||
glCheck(glDisable(GL_ALPHA_TEST));
|
||||
glCheck(glDisable(GL_SCISSOR_TEST));
|
||||
@ -529,11 +611,14 @@ void RenderTarget::resetGLStates()
|
||||
glCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glCheck(glEnableClientState(GL_COLOR_ARRAY));
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
glCheck(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
||||
m_cache.scissorEnabled = false;
|
||||
m_cache.stencilEnabled = false;
|
||||
m_cache.glStatesSet = true;
|
||||
|
||||
// Apply the default SFML states
|
||||
applyBlendMode(BlendAlpha);
|
||||
applyStencilMode(StencilMode());
|
||||
applyTexture(nullptr);
|
||||
if (shaderAvailable)
|
||||
applyShader(nullptr);
|
||||
@ -663,6 +748,43 @@ void RenderTarget::applyBlendMode(const BlendMode& mode)
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyStencilMode(const StencilMode& mode)
|
||||
{
|
||||
using RenderTargetImpl::stencilFunctionToGlConstant;
|
||||
using RenderTargetImpl::stencilOperationToGlConstant;
|
||||
|
||||
// Fast path if we have a default (disabled) stencil mode
|
||||
if (mode == StencilMode())
|
||||
{
|
||||
if (m_cache.stencilEnabled)
|
||||
{
|
||||
glCheck(glDisable(GL_STENCIL_TEST));
|
||||
glCheck(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
||||
|
||||
m_cache.stencilEnabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Apply the stencil mode
|
||||
if (!m_cache.stencilEnabled)
|
||||
glCheck(glEnable(GL_STENCIL_TEST));
|
||||
|
||||
glCheck(glStencilOp(GL_KEEP,
|
||||
stencilOperationToGlConstant(mode.stencilUpdateOperation),
|
||||
stencilOperationToGlConstant(mode.stencilUpdateOperation)));
|
||||
glCheck(glStencilFunc(stencilFunctionToGlConstant(mode.stencilComparison),
|
||||
static_cast<int>(mode.stencilReference.value),
|
||||
mode.stencilMask.value));
|
||||
|
||||
m_cache.stencilEnabled = true;
|
||||
}
|
||||
|
||||
m_cache.lastStencilMode = mode;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyTransform(const Transform& transform)
|
||||
{
|
||||
@ -732,6 +854,14 @@ void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
|
||||
if (!m_cache.enable || (states.blendMode != m_cache.lastBlendMode))
|
||||
applyBlendMode(states.blendMode);
|
||||
|
||||
// Apply the stencil mode
|
||||
if (!m_cache.enable || (states.stencilMode != m_cache.lastStencilMode))
|
||||
applyStencilMode(states.stencilMode);
|
||||
|
||||
// Mask the color buffer off if necessary
|
||||
if (states.stencilMode.stencilOnly)
|
||||
glCheck(glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
|
||||
|
||||
// Apply the texture
|
||||
if (!m_cache.enable || (states.texture && states.texture->m_fboAttachment))
|
||||
{
|
||||
@ -780,6 +910,10 @@ void RenderTarget::cleanupDraw(const RenderStates& states)
|
||||
if (states.texture && states.texture->m_fboAttachment)
|
||||
applyTexture(nullptr);
|
||||
|
||||
// Mask the color buffer back on if necessary
|
||||
if (states.stencilMode.stencilOnly)
|
||||
glCheck(glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
||||
|
||||
// Re-enable the cache at the end of the draw if it was disabled
|
||||
m_cache.enable = true;
|
||||
}
|
||||
|
@ -85,7 +85,8 @@ bool RenderTexture::create(const Vector2u& size, const ContextSettings& settings
|
||||
}
|
||||
|
||||
// Initialize the render texture
|
||||
if (!m_impl->create(size, m_texture.m_texture, settings))
|
||||
// We pass the actual size of our texture since OpenGL ES requires that all attachments have identical sizes
|
||||
if (!m_impl->create(m_texture.m_actualSize, m_texture.m_texture, settings))
|
||||
return false;
|
||||
|
||||
// We can now initialize the render target part
|
||||
|
@ -153,9 +153,6 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
if (settings.antialiasingLevel && !(GLEXT_framebuffer_multisample && GLEXT_framebuffer_blit))
|
||||
return false;
|
||||
|
||||
if (settings.stencilBits && !GLEXT_packed_depth_stencil)
|
||||
return false;
|
||||
|
||||
m_sRgb = settings.sRgbCapable && GL_EXT_texture_sRGB;
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
@ -176,14 +173,17 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
if (!settings.antialiasingLevel)
|
||||
{
|
||||
// Create the depth/stencil buffer if requested
|
||||
if (settings.stencilBits)
|
||||
if (settings.stencilBits && settings.depthBits)
|
||||
{
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
if (!GLEXT_packed_depth_stencil)
|
||||
{
|
||||
err() << "Impossible to create render texture (combined depth/stencil buffer not supported)"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint depthStencil = 0;
|
||||
glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
|
||||
@ -200,17 +200,8 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = true;
|
||||
m_stencil = true;
|
||||
|
||||
#else
|
||||
|
||||
m_stencil = false;
|
||||
|
||||
err() << "Impossible to create render texture (failed to create the attached depth/stencil buffer)"
|
||||
<< std::endl;
|
||||
return false;
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
}
|
||||
else if (settings.depthBits)
|
||||
{
|
||||
@ -228,6 +219,29 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
GLEXT_GL_DEPTH_COMPONENT,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = true;
|
||||
m_stencil = false;
|
||||
}
|
||||
else if (settings.stencilBits)
|
||||
{
|
||||
GLuint depthStencil = 0;
|
||||
glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
|
||||
m_depthStencilBuffer = depthStencil;
|
||||
if (!m_depthStencilBuffer)
|
||||
{
|
||||
err() << "Impossible to create render texture (failed to create the attached stencil buffer)"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
|
||||
glCheck(GLEXT_glRenderbufferStorage(GLEXT_GL_RENDERBUFFER,
|
||||
GLEXT_GL_STENCIL_INDEX8,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = false;
|
||||
m_stencil = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -253,7 +267,7 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
// Create the multisample depth/stencil buffer if requested
|
||||
if (settings.stencilBits)
|
||||
if (settings.stencilBits && settings.depthBits)
|
||||
{
|
||||
GLuint depthStencil = 0;
|
||||
glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
|
||||
@ -272,6 +286,7 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = true;
|
||||
m_stencil = true;
|
||||
}
|
||||
else if (settings.depthBits)
|
||||
@ -292,6 +307,31 @@ bool RenderTextureImplFBO::create(const Vector2u& size, unsigned int textureId,
|
||||
GLEXT_GL_DEPTH_COMPONENT,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = true;
|
||||
m_stencil = false;
|
||||
}
|
||||
else if (settings.stencilBits)
|
||||
{
|
||||
GLuint depthStencil = 0;
|
||||
glCheck(GLEXT_glGenRenderbuffers(1, &depthStencil));
|
||||
m_depthStencilBuffer = depthStencil;
|
||||
if (!m_depthStencilBuffer)
|
||||
{
|
||||
err() << "Impossible to create render texture (failed to create the attached multisample "
|
||||
"stencil buffer)"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
glCheck(GLEXT_glBindRenderbuffer(GLEXT_GL_RENDERBUFFER, m_depthStencilBuffer));
|
||||
glCheck(GLEXT_glRenderbufferStorageMultisample(GLEXT_GL_RENDERBUFFER,
|
||||
static_cast<GLsizei>(settings.antialiasingLevel),
|
||||
GLEXT_GL_STENCIL_INDEX8,
|
||||
static_cast<GLsizei>(size.x),
|
||||
static_cast<GLsizei>(size.y)));
|
||||
|
||||
m_depth = false;
|
||||
m_stencil = true;
|
||||
}
|
||||
|
||||
m_multisample = true;
|
||||
@ -368,13 +408,14 @@ bool RenderTextureImplFBO::createFrameBuffer()
|
||||
|
||||
// Link the depth/stencil renderbuffer to the frame buffer
|
||||
if (!m_multisample && m_depthStencilBuffer)
|
||||
{
|
||||
if (m_depth)
|
||||
{
|
||||
glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER,
|
||||
GLEXT_GL_DEPTH_ATTACHMENT,
|
||||
GLEXT_GL_RENDERBUFFER,
|
||||
m_depthStencilBuffer));
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
}
|
||||
|
||||
if (m_stencil)
|
||||
{
|
||||
@ -383,8 +424,6 @@ bool RenderTextureImplFBO::createFrameBuffer()
|
||||
GLEXT_GL_RENDERBUFFER,
|
||||
m_depthStencilBuffer));
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// Link the texture to the frame buffer
|
||||
@ -428,11 +467,14 @@ bool RenderTextureImplFBO::createFrameBuffer()
|
||||
|
||||
// Link the depth/stencil renderbuffer to the frame buffer
|
||||
if (m_depthStencilBuffer)
|
||||
{
|
||||
if (m_depth)
|
||||
{
|
||||
glCheck(GLEXT_glFramebufferRenderbuffer(GLEXT_GL_FRAMEBUFFER,
|
||||
GLEXT_GL_DEPTH_ATTACHMENT,
|
||||
GLEXT_GL_RENDERBUFFER,
|
||||
m_depthStencilBuffer));
|
||||
}
|
||||
|
||||
if (m_stencil)
|
||||
{
|
||||
|
@ -149,6 +149,7 @@ private:
|
||||
std::unique_ptr<Context> m_context; //!< Backup OpenGL context, used when none already exist
|
||||
unsigned int m_textureId{}; //!< The ID of the texture to attach to the FBO
|
||||
bool m_multisample{}; //!< Whether we have to create a multisample frame buffer as well
|
||||
bool m_depth{}; //!< Whether we have depth attachment
|
||||
bool m_stencil{}; //!< Whether we have stencil attachment
|
||||
bool m_sRgb{}; //!< Whether we need to encode drawn pixels into sRGB color space
|
||||
};
|
||||
|
61
src/SFML/Graphics/StencilMode.cpp
Normal file
61
src/SFML/Graphics/StencilMode.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
StencilValue::StencilValue(int theValue) : value(static_cast<unsigned int>(theValue))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
StencilValue::StencilValue(unsigned int theValue) : value(theValue)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool operator==(const StencilMode& left, const StencilMode& right)
|
||||
{
|
||||
return left.stencilUpdateOperation == right.stencilUpdateOperation &&
|
||||
left.stencilComparison == right.stencilComparison &&
|
||||
left.stencilReference.value == right.stencilReference.value &&
|
||||
left.stencilMask.value == right.stencilMask.value && left.stencilOnly == right.stencilOnly;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool operator!=(const StencilMode& left, const StencilMode& right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
} // namespace sf
|
@ -92,6 +92,7 @@ set(GRAPHICS_SRC
|
||||
Graphics/Image.test.cpp
|
||||
Graphics/Rect.test.cpp
|
||||
Graphics/RectangleShape.test.cpp
|
||||
Graphics/Render.test.cpp
|
||||
Graphics/RenderStates.test.cpp
|
||||
Graphics/RenderTarget.test.cpp
|
||||
Graphics/RenderTexture.test.cpp
|
||||
@ -99,6 +100,7 @@ set(GRAPHICS_SRC
|
||||
Graphics/Shader.test.cpp
|
||||
Graphics/Shape.test.cpp
|
||||
Graphics/Sprite.test.cpp
|
||||
Graphics/StencilMode.test.cpp
|
||||
Graphics/Text.test.cpp
|
||||
Graphics/Texture.test.cpp
|
||||
Graphics/Transform.test.cpp
|
||||
|
240
test/Graphics/Render.test.cpp
Normal file
240
test/Graphics/Render.test.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/RectangleShape.hpp>
|
||||
#include <SFML/Graphics/RenderTexture.hpp>
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <GraphicsUtil.hpp>
|
||||
|
||||
TEST_CASE("[Graphics] Render Tests", runDisplayTests())
|
||||
{
|
||||
SECTION("Stencil Tests")
|
||||
{
|
||||
sf::RenderTexture renderTexture;
|
||||
REQUIRE(renderTexture.create({100, 100}, sf::ContextSettings(0, 8)) == true);
|
||||
renderTexture.clear(sf::Color::Red, 127);
|
||||
|
||||
sf::RectangleShape shape1({100, 100});
|
||||
shape1.setFillColor(sf::Color::Green);
|
||||
sf::RectangleShape shape2({100, 100});
|
||||
shape2.setFillColor(sf::Color::Blue);
|
||||
|
||||
SECTION("Stencil-Only")
|
||||
{
|
||||
renderTexture.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Keep, 1, 0xFF, true});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
}
|
||||
|
||||
SECTION("Comparisons")
|
||||
{
|
||||
SECTION("Always")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Keep, 1, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Equal")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Keep, 126, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Greater")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Keep, 126, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Keep, 128, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("GreaterEqual")
|
||||
{
|
||||
renderTexture.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::GreaterEqual,
|
||||
sf::StencilUpdateOperation::Keep,
|
||||
126,
|
||||
0xFF,
|
||||
false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::GreaterEqual,
|
||||
sf::StencilUpdateOperation::Keep,
|
||||
127,
|
||||
0xFF,
|
||||
false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
renderTexture.draw(shape2,
|
||||
sf::StencilMode{sf::StencilComparison::GreaterEqual,
|
||||
sf::StencilUpdateOperation::Keep,
|
||||
128,
|
||||
0xFF,
|
||||
false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Blue);
|
||||
}
|
||||
|
||||
SECTION("Less")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Less, sf::StencilUpdateOperation::Keep, 128, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Less, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Less, sf::StencilUpdateOperation::Keep, 126, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("LessEqual")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::LessEqual, sf::StencilUpdateOperation::Keep, 128, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::LessEqual, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
renderTexture
|
||||
.draw(shape2,
|
||||
sf::StencilMode{sf::StencilComparison::LessEqual, sf::StencilUpdateOperation::Keep, 126, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Blue);
|
||||
}
|
||||
|
||||
SECTION("Never")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Never, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
}
|
||||
|
||||
SECTION("NotEqual")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Red);
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::NotEqual, sf::StencilUpdateOperation::Keep, 128, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Updating")
|
||||
{
|
||||
SECTION("Decrement")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Decrement, 127, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Decrement, 126, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Increment")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Increment, 127, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Increment, 128, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Invert")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Invert, 127, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Invert, 0x80, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Keep")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Keep, 127, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Keep, 127, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Replace")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Replace, 255, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 255, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
|
||||
SECTION("Zero")
|
||||
{
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Always, sf::StencilUpdateOperation::Zero, 127, 0xFF, true});
|
||||
renderTexture
|
||||
.draw(shape1,
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Zero, 0, 0xFF, false});
|
||||
renderTexture.display();
|
||||
CHECK(renderTexture.getTexture().copyToImage().getPixel({50, 50}) == sf::Color::Green);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
{
|
||||
const sf::RenderStates renderStates;
|
||||
CHECK(renderStates.blendMode == sf::BlendMode());
|
||||
CHECK(renderStates.stencilMode == sf::StencilMode{});
|
||||
CHECK(renderStates.transform == sf::Transform());
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
@ -37,17 +38,30 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
sf::BlendMode::Equation::Max);
|
||||
const sf::RenderStates renderStates(blendMode);
|
||||
CHECK(renderStates.blendMode == blendMode);
|
||||
CHECK(renderStates.stencilMode == sf::StencilMode{});
|
||||
CHECK(renderStates.transform == sf::Transform());
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
CHECK(renderStates.shader == nullptr);
|
||||
}
|
||||
|
||||
SECTION("StencilMode constructor")
|
||||
{
|
||||
const sf::StencilMode stencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true};
|
||||
const sf::RenderStates renderStates(stencilMode);
|
||||
CHECK(renderStates.blendMode == sf::BlendMode());
|
||||
CHECK(renderStates.stencilMode == stencilMode);
|
||||
CHECK(renderStates.transform == sf::Transform());
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
CHECK(renderStates.shader == nullptr);
|
||||
}
|
||||
|
||||
SECTION("Transform constructor")
|
||||
{
|
||||
const sf::Transform transform(10, 9, 8, 7, 6, 5, 4, 3, 2);
|
||||
const sf::RenderStates renderStates(transform);
|
||||
CHECK(renderStates.blendMode == sf::BlendMode());
|
||||
CHECK(renderStates.stencilMode == sf::StencilMode{});
|
||||
CHECK(renderStates.transform == transform);
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
@ -59,6 +73,7 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
const sf::Texture* texture = nullptr;
|
||||
const sf::RenderStates renderStates(texture);
|
||||
CHECK(renderStates.blendMode == sf::BlendMode());
|
||||
CHECK(renderStates.stencilMode == sf::StencilMode{});
|
||||
CHECK(renderStates.transform == sf::Transform());
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(renderStates.texture == texture);
|
||||
@ -70,6 +85,7 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
const sf::Shader* shader = nullptr;
|
||||
const sf::RenderStates renderStates(shader);
|
||||
CHECK(renderStates.blendMode == sf::BlendMode());
|
||||
CHECK(renderStates.stencilMode == sf::StencilMode{});
|
||||
CHECK(renderStates.transform == sf::Transform());
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
@ -84,9 +100,11 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
sf::BlendMode::Factor::OneMinusDstAlpha,
|
||||
sf::BlendMode::Factor::DstAlpha,
|
||||
sf::BlendMode::Equation::Max);
|
||||
const sf::StencilMode stencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true};
|
||||
const sf::Transform transform(10, 2, 3, 4, 50, 40, 30, 20, 10);
|
||||
const sf::RenderStates renderStates(blendMode, transform, sf::CoordinateType::Normalized, nullptr, nullptr);
|
||||
const sf::RenderStates renderStates(blendMode, stencilMode, transform, sf::CoordinateType::Normalized, nullptr, nullptr);
|
||||
CHECK(renderStates.blendMode == blendMode);
|
||||
CHECK(renderStates.stencilMode == stencilMode);
|
||||
CHECK(renderStates.transform == transform);
|
||||
CHECK(renderStates.coordinateType == sf::CoordinateType::Normalized);
|
||||
CHECK(renderStates.texture == nullptr);
|
||||
@ -97,6 +115,7 @@ TEST_CASE("[Graphics] sf::RenderStates")
|
||||
SECTION("Default constant")
|
||||
{
|
||||
CHECK(sf::RenderStates::Default.blendMode == sf::BlendMode());
|
||||
CHECK(sf::RenderStates::Default.stencilMode == sf::StencilMode{});
|
||||
CHECK(sf::RenderStates::Default.transform == sf::Transform());
|
||||
CHECK(sf::RenderStates::Default.coordinateType == sf::CoordinateType::Pixels);
|
||||
CHECK(sf::RenderStates::Default.texture == nullptr);
|
||||
|
@ -32,6 +32,10 @@ TEST_CASE("[Graphics] sf::RenderTexture", runDisplayTests())
|
||||
CHECK(!renderTexture.isRepeated());
|
||||
CHECK(renderTexture.getSize() == sf::Vector2u(480, 360));
|
||||
CHECK(!renderTexture.isSrgb());
|
||||
CHECK(renderTexture.create({360, 480}));
|
||||
CHECK(renderTexture.getSize() == sf::Vector2u(360, 480));
|
||||
CHECK(renderTexture.create({100, 100}, sf::ContextSettings(8, 0)));
|
||||
CHECK(renderTexture.create({100, 100}, sf::ContextSettings(0, 8)));
|
||||
}
|
||||
|
||||
SECTION("getMaximumAntialiasingLevel()")
|
||||
|
71
test/Graphics/StencilMode.test.cpp
Normal file
71
test/Graphics/StencilMode.test.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
TEST_CASE("[Graphics] sf::StencilMode")
|
||||
{
|
||||
SECTION("Type traits")
|
||||
{
|
||||
STATIC_CHECK(std::is_copy_constructible_v<sf::StencilMode>);
|
||||
STATIC_CHECK(std::is_copy_assignable_v<sf::StencilMode>);
|
||||
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::StencilMode>);
|
||||
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::StencilMode>);
|
||||
}
|
||||
|
||||
SECTION("Construction")
|
||||
{
|
||||
const sf::StencilMode stencilMode;
|
||||
CHECK(stencilMode.stencilComparison == sf::StencilComparison::Always);
|
||||
CHECK(stencilMode.stencilUpdateOperation == sf::StencilUpdateOperation::Keep);
|
||||
CHECK(stencilMode.stencilReference.value == 0u);
|
||||
CHECK(stencilMode.stencilMask.value == ~0u);
|
||||
CHECK(stencilMode.stencilOnly == false);
|
||||
}
|
||||
|
||||
SECTION("Stencil value type traits")
|
||||
{
|
||||
STATIC_CHECK(!std::is_default_constructible_v<sf::StencilValue>);
|
||||
STATIC_CHECK(!std::is_convertible_v<bool, sf::StencilValue>);
|
||||
STATIC_CHECK(!std::is_convertible_v<char, sf::StencilValue>);
|
||||
STATIC_CHECK(!std::is_convertible_v<unsigned char, sf::StencilValue>);
|
||||
STATIC_CHECK(!std::is_convertible_v<short, sf::StencilValue>);
|
||||
STATIC_CHECK(!std::is_convertible_v<unsigned short, sf::StencilValue>);
|
||||
STATIC_CHECK(std::is_convertible_v<int, sf::StencilValue>);
|
||||
STATIC_CHECK(std::is_convertible_v<unsigned int, sf::StencilValue>);
|
||||
}
|
||||
|
||||
SECTION("Stencil value construction")
|
||||
{
|
||||
const sf::StencilValue stencilValue{0};
|
||||
CHECK(stencilValue.value == 0u);
|
||||
}
|
||||
|
||||
SECTION("Operators")
|
||||
{
|
||||
SECTION("operator==")
|
||||
{
|
||||
CHECK(sf::StencilMode{} == sf::StencilMode{});
|
||||
CHECK(sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true} ==
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
|
||||
CHECK_FALSE(sf::StencilMode{} ==
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
CHECK_FALSE(sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Invert, 0, ~0u, false} ==
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
}
|
||||
|
||||
SECTION("operator!=")
|
||||
{
|
||||
CHECK_FALSE(sf::StencilMode{} != sf::StencilMode{});
|
||||
CHECK_FALSE(sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true} !=
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
|
||||
CHECK(sf::StencilMode{} !=
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
CHECK(sf::StencilMode{sf::StencilComparison::Greater, sf::StencilUpdateOperation::Invert, 0, ~0u, false} !=
|
||||
sf::StencilMode{sf::StencilComparison::Equal, sf::StencilUpdateOperation::Replace, 1, 0u, true});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#include <SFML/Graphics/BlendMode.hpp>
|
||||
#include <SFML/Graphics/Color.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/Graphics/StencilMode.hpp>
|
||||
#include <SFML/Graphics/Transform.hpp>
|
||||
|
||||
#include <GraphicsUtil.hpp>
|
||||
@ -17,6 +18,59 @@ std::ostream& operator<<(std::ostream& os, const BlendMode& blendMode)
|
||||
<< ", " << static_cast<int>(blendMode.alphaEquation) << " )";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const StencilComparison& comparison)
|
||||
{
|
||||
switch (comparison)
|
||||
{
|
||||
case StencilComparison::Never:
|
||||
return os << "Never";
|
||||
case StencilComparison::Less:
|
||||
return os << "Less";
|
||||
case StencilComparison::LessEqual:
|
||||
return os << "LessEqual";
|
||||
case StencilComparison::Greater:
|
||||
return os << "Greater";
|
||||
case StencilComparison::GreaterEqual:
|
||||
return os << "GreaterEqual";
|
||||
case StencilComparison::Equal:
|
||||
return os << "Equal";
|
||||
case StencilComparison::NotEqual:
|
||||
return os << "NotEqual";
|
||||
case StencilComparison::Always:
|
||||
return os << "Always";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const StencilUpdateOperation& updateOperation)
|
||||
{
|
||||
switch (updateOperation)
|
||||
{
|
||||
case StencilUpdateOperation::Keep:
|
||||
return os << "Keep";
|
||||
case StencilUpdateOperation::Zero:
|
||||
return os << "Zero";
|
||||
case StencilUpdateOperation::Replace:
|
||||
return os << "Replace";
|
||||
case StencilUpdateOperation::Increment:
|
||||
return os << "Increment";
|
||||
case StencilUpdateOperation::Decrement:
|
||||
return os << "Decrement";
|
||||
case StencilUpdateOperation::Invert:
|
||||
return os << "Invert";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const StencilMode& stencilMode)
|
||||
{
|
||||
return os << "( " << stencilMode.stencilComparison << ", " << stencilMode.stencilUpdateOperation << ", "
|
||||
<< stencilMode.stencilReference.value << ", " << stencilMode.stencilMask.value << ", "
|
||||
<< stencilMode.stencilOnly << " )";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Color& color)
|
||||
{
|
||||
return os << "0x" << std::hex << color.toInteger() << std::dec << " (r=" << int{color.r} << ", g=" << int{color.g}
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace sf
|
||||
{
|
||||
struct BlendMode;
|
||||
struct StencilMode;
|
||||
class Color;
|
||||
class Transform;
|
||||
|
||||
@ -19,6 +20,7 @@ template <typename>
|
||||
class Rect;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const BlendMode& blendMode);
|
||||
std::ostream& operator<<(std::ostream& os, const StencilMode& stencilMode);
|
||||
std::ostream& operator<<(std::ostream& os, const Color& color);
|
||||
std::ostream& operator<<(std::ostream& os, const Transform& transform);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user