SFML / SFML

Simple and Fast Multimedia Library
https://www.sfml-dev.org/
zlib License
10.23k stars 1.72k forks source link

Implement rendering masks #1

Closed LaurentGomila closed 6 months ago

LaurentGomila commented 13 years ago

Add a sf::ClippingMask class, which is used to clip rendered objects to a specific region of 2D world.

There are many OpenGL options to implement it, the best one should be clip planes.

OniLink commented 13 years ago

This sounds like a good feature. So it just forces rendering to be limited to a specific region?

LaurentGomila commented 13 years ago

Yes.

Mon-Ouie commented 13 years ago

Would there be any advantage in using this over an sf::View by adapting the viewport and the size and center of the view? And what if someone tries to use both a view and clipping mask?

LaurentGomila commented 13 years ago

Clipping masks can be simulated with the current API by combining viewport and size of a sf::View, you're perfectly right.

However it has a few drawbacks:

Moreover, clipping masks might be extended in the future to have more features (pixel based masks, polygonal masks, etc.).

OniLink commented 13 years ago

Tell me, would ClippingMask automatically check the location any drawn drawables and cut them out of the rendering if they're out of the mask?

LaurentGomila commented 13 years ago

Nop. Clipping masks will be implemented using their OpenGL equivalent, and that's all (so clipping will happen on the GPU).

I won't add custom optimizations on top of it -- at least for now.

OniLink commented 13 years ago

Alright.

hsdk123 commented 10 years ago

Hi, is this currently being looked into? This definitely sounds like a great feature.

Bromeon commented 10 years ago

As you see from the milestone, it's currently not a top priority, but it could be investigated once the important tasks for SFML 2.2 are done.

CelticMinstrel commented 10 years ago

Would this allow for things like circular masks or masks generated from a black-and-white image?

I was using glScissor for rectangular clipping and attempting to use the stencil buffer for the above two types of clipping. I haven't gotten it to work yet.

LaurentGomila commented 10 years ago

Would this allow for things like circular masks or masks generated from a black-and-white image?

I don't know yet, nothing has been decided.

StelarCF commented 10 years ago

This would be a really good addition, especially for UI.

CelticMinstrel commented 10 years ago

Just for information, I got the aforementioned two to work, using the stencil buffer for the circular mask; and I ended up using a shader for the image mask (basically using a second image as an alpha channel).

Mischa-Alff commented 9 years ago

I'm interested in this feature. How would this look API-wise? I was thinking of passing a sf::Shape and clip mode to a sf::ClipMask class (placeholder name), and then setting it in sf::RenderStates. It would then use OpenGL's stencil buffer. As was previously mentioned, this functionality is really useful for implementing UI stuff.

LaurentGomila commented 9 years ago

We must decide which features we want exactly for this:

And do we clip in scene coordinates or in window coordinates? What does OpenGL 1.x allow in terms of implementation?

Mischa-Alff commented 9 years ago

glScissor does clipping in window coordinates, yet GL's stencil stuff is done in scene coordinates. I think using scene coordinates is more intuitive, since that's what sf::Shape and whatnot use. glScissor only allows rectangular clipping, and although most of the time that is all that is needed, I'm sure some would be glad to be able to have custom-shape clipping.

I'm not sure how image/sprite clipping would work. Wouldn't that just be a blendmode or something?

MarioLiebisch commented 9 years ago

It's essentially similar to depth testing. You draw to the scissor buffer and then compare pixels in the scissor buffer to a reference value to determine whether to render or not (or what to do). With that you can do all kind of neat things, like limiting how often a specific pixel is drawn. More information can be found here.

LaurentGomila commented 9 years ago

scissor buffer

Stencil buffer ;)

The stencil buffer is well supported and allows a wide range of possibilities, so it is the best candidate. However since it can be disabled (and is currently not enabled by default) in the context settings, 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.

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.

Another question is: do we allow only one active mask, or do we provide the ability to add multiple masks?

We should think about the most common use cases of clipping masks in order to answer efficiently to these questions.

Mischa-Alff commented 9 years ago

If the application uses the stencil buffer (via an sf::ClipMask), it can simply enable it, no?

Regarding the clipping area, I think the user might want to define a mask using multiple shapes if possible.

In my opinion, there are many uses for clipping masks, but the single one that comes up most often is probably UI stuff.

LaurentGomila commented 9 years ago

If the application uses the stencil buffer (via an sf::ClipMask), it can simply enable it, no?

It must be decided at window creation. And wouldn't it be worst to force stencil buffer if the user had explicitly disabled it?

Regarding the clipping area, I think the user might want to define a mask using multiple shapes if possible.

Keep in mind that we must keep the API simple enough. Which often means not providing everything that can be done. But yes, that's a possibility.

In my opinion, there are many uses for clipping masks, but the single one that comes up most often is probably UI stuff.

Yes, this is probably the most common one.

CelticMinstrel commented 9 years ago

This sounds good so far. As I mentioned earlier, my personal need is for elliptical clipping regions (so, an sf::Shape) and for pixel-based masks (so, using a monochrome image to specify the exact extent of the mask). I wasn't able to solve the latter problem with the stencil buffer, though I feel like I should have been able to.

I don't think it's terribly complicated to make a class that will compose an arbitrary number of sf::Shapes into a region - then when populating the stencil buffer, you just need to "draw" those shapes in sequence. You can even allow subtraction of a shape from the region, rather than addition.

It might be complicated to support pixel-based masks, though.

zsbzsb commented 9 years ago

4 years later and 841 issues/pulls later...... #846 check it out

aaaaaaaaargh commented 5 years ago

I just came back to SFML after a couple of years and I'm honestly nearly losing all my hopes about why this it not fixed by now.

There is a PR by @zsbzsb which looks nice and well implemented, so I'm wondering why noone else seems to be considering this a massive lack of a basic feature here.

I mean, I was working with a hell lot of libraries over the past 20 years and this is something that even old libraries like allegro come up with since decades.

I am calling on you to please check and merge @zsbzsb 's proposal as soon as possible.

Really no offense guys, you do great work maintaining SFML, so consider this just a friendly but serious reminder of how important clip masks are.

binary1248 commented 5 years ago

@aaaaaaaaargh So... since you mention allegro... what concrete functions does allegro provide that provides non-rectangular clipping? That is the point that is so contentious now. If you wanted rectangular clipping, just use an sf::View. There is no need to hold your breath for this feature.

aaaaaaaaargh commented 5 years ago

@binary1248 allegro 4 had masked_blit() which pretty much does what you're asking for. When speaking about 5 i am not sure, but I guess you could do it using al_draw_bitmap_region or something like that. Please remember that due to its heritage allegro 5 implements most of its graphics functions using global application states just as GL does, so this might not be too hard to achieve.

I'm afraid I wasn't talking about rectangular clipping at all, I am talking about opacity or clip maps which, at least in my humble opinion, should be a feature in a graphics library nowadays.

Again, I don't wan't to discredit your work, I know how demanding it can be to work for free on such a big thing like SFML. I was just pointing out that work has already been done like 4 years ago by @zsbzsb and I think that deserves a little bit of attention as well.

binary1248 commented 5 years ago

@aaaaaaaaargh Skimming through https://liballeg.org/stabledocs/en/alleg014.html and https://liballeg.org/a5docs/trunk/graphics.html I couldn't find any functions that provide support for anything non-rectangular.

What many people tend to easily forget is that we aren't talking about the feature in and of itself, we are also talking about its concrete implementation. sfml-graphics does its drawing fully hardware-accelerated, and we want to keep it that way. No matter how sought after a feature is, if it cannot be done on a GPU to keep frame rates acceptable it won't be done.

@zsbzsb's implementation was surely the first to show up, but there were at least 2 other proposals, including mine which was a bit too low level for some people. If there is no consensus on how to proceed API-wise or implementation-wise then features, as much as they are sought after, will just end up in a deadlock like this one.

The best thing you can do is either start a new discussion or continue the existing one and try to muster support and someone who will champion an implementation that is ripe enough for a formal review.

As painful as it might sound, even if you find a feature useful the main reason why it hasn't been worked on is that there just hasn't been an overwhelming amount of interest from the community for it, regardless of how old it is.

eXpl0it3r commented 6 months ago

Closing this, as #1451 has been merged on master

...finally! 🥳