Recreated from #842
This is ready for a code review, hoping for a SFML 2.4 inclusion. This implements #1, yes the very first issue. :smile:
I based my branch on /feature/gl_dev_new due to the OpenGL changes. Clipping is done with the stencil buffer which gets enabled when a mask is applied to the render states.
Some points from #1 are answered below about this implementation.
And do we clip in scene coordinates or in window coordinates?
Clipping is done in scene coordinates.
However since it can be disabled (and is currently not enabled by default) in the context settings.
It is now enabled by default in the context and render texture constructors.
it implies that the user can disable clipping masks, without even knowing it. So this must be at least well documented, and even enforced if possible.
It is now noted in the documentation that disabling stencil buffer will disable clipping masks. As for enforcing it? Its not really needed, if the user disables it - it is their fault because it is clearly stated.
So the main problem is to decide what we use to define the clipping area. We could start with a const sf::Drawable*
to have maximum flexibility.
Clipping area is defined by the sf::ClippingMask
class which is a container for multiple const sf::Drawable*
pointers.
Another question is: do we allow only one active mask, or do we provide the ability to add multiple masks?
Only 1 mask is active at one time, but it can be defined by multiple drawables.
As with my other PR (#840), please review and test and then give feedback. Even textures with alpha channels are supported.
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window({ 800, 600 }, "Clipping Mask Test");
window.setVerticalSyncEnabled(true);
// create a circle for part of the clipping mask
sf::CircleShape keyholetop(50);
keyholetop.setOrigin({ 50, 50 });
// create a square for part of the clipping mask
sf::RectangleShape keyholebody({ 36, 150 });
keyholebody.setOrigin({ 18, 0 });
// create the clipping mask
sf::ClippingMask clipmask;
// add the shapes to the clipping mask
// sf::ClippingMask behaves like sf::VertexArray
// so you can append any sf::Drawable to the mask
// the mask will not copy the sf::Drawable, it only stores a pointer
clipmask.append(keyholetop);
clipmask.append(keyholebody);
sf::Texture background;
// use any background image
// I used the image from opengl example
background.loadFromFile("sfml/examples/opengl/resources/background.jpg");
sf::Sprite backgroundsprite(background);
// set a clipping area
// for this example exlude the area 50px from the borders
window.setClippingArea({ 50, 50, 700, 500 });
while (window.isOpen())
{
sf::Event e;
while (window.pollEvent(e))
{
if (e.type == sf::Event::Closed)
window.close();
}
// get mouse position
sf::Vector2f mousepos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
// update the mask position
clipmask.setPosition(mousepos);
//assign the clipping mask to the window
window.setClippingMask(clipmask);
window.clear(sf::Color::Blue);
window.draw(backgroundsprite);
window.display();
}
}

I just updated the API. I removed the clipping mask from the render states and instead added function the render target class for setting the mask. Also all clipping is now cached instead of redrawn every time.
And I will say it again: Please test and give feedback - even if you don't test this branch, at least comment on the API design, thanks :smile:
There was a total of 6 functions added to the render target class.
clearClipping[Area|Mask]();
setClipping[Area|Mask](...);
getClipping[Area|Mask]();
Clipping masks are the same as the previous commits, basically a list of drawables that allow users to define custom shapes / pixel based masks. The masks are implemented with the stencil buffer.
Clipping areas on the other hand are limited to a single IntRect that is defined in window coordinates. The clipping area is implemented using glScissor(...)
which should provide faster, simpler clipping for those who just need it for basic GUIs.
The clipping mask on the other hand is heavier and uses the stencil buffer for clipping. It works in scene coordinates and is used for more complex masks.
Both clipping modes are applied like the view is. To set a clipping mode you first call setClippingXXX(...)
with the appropriate parameters. The clipping mode will be cached until it is either cleared or updated (another set call).
feature m:sfml-graphics s:superseded