Salut chère communauté !
Je travaille actuellement sur un gros projet, mais je bloque malheureusement sur une technique en particulier.
Il s'agit d'utiliser une classe Canevas, dérivant de sf::Drawable et sf::Transformable et pouvant contenir d'autres sf::Drawable, donc potentiellement d'autres Canevas.
Le but est d'obtenir des espaces de dessin pouvant être décris les uns par rapport aux autres, jusque là, rien de sorcier.
Là ou je bloque, c'est pour la gestion du clipping. En effet, je souhaiterai que cet espace de dessin soit "fermé", qu'aucune entité dessinable enfant (peu importe son degrés de parenté), n'en sorte.
Après quelques recherches voici les pistes qui me sont données :
- Utiliser sf::View et son viewport : d'un côté ça m'arrange d'ajouter le système des vues à Canevas, d'un autre je n'ai jamais réussi à l'adapter correctement à mon problème malgré la doc.,
- Utiliser comme il sera présenté par la suite la fonction glScissor de openGL, solution intéressante mais néanmoins limitée dans mon cas, puisque dans mon exemple, seul le dernier appel à cette fonction est effectif,
- Utiliser les clipPlanes de openGL, mais parait-il ils sont très gourmands en ressources,
- Utiliser le stencil buffer, solution conseillée sur de nombreux forums.
J'ai donc simplifié le tout pour faire un exemple minimal directement compilable, utilisant la fonction glScissor :
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
struct Canevas : public sf::Drawable, public sf::Transformable {
std::vector<sf::Drawable*> drawables;
sf::FloatRect clipping;
protected:
void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform.combine(getTransform());
sf::Vector2f pos = states.transform.transformPoint({clipping.left, clipping.height + clipping.top});
glPushAttrib(GL_SCISSOR_BIT);
glEnable(GL_SCISSOR_TEST);
glScissor(pos.x, target.getSize().y - pos.y, clipping.width, clipping.height);
for( auto& drawable : drawables )
target.draw(*drawable, states);
glDisable(GL_SCISSOR_TEST);
glPopAttrib();
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(400, 400, 32), "Test");
window.setVerticalSyncEnabled(true);
/// CANEVAS 1 ///
sf::RectangleShape shape1;
shape1.setFillColor(sf::Color::Blue);
shape1.setSize({200, 200});
Canevas canevas1;
canevas1.setPosition({50, 50});
canevas1.clipping = {0, 0, 200, 200};
canevas1.drawables.push_back(&shape1);
/// CANEVAS 2 ///
sf::RectangleShape shape2;
shape2.setFillColor(sf::Color::Green);
shape2.setSize({200, 200});
sf::RectangleShape shape3;
shape3.setPosition(50, 50);
shape3.setFillColor(sf::Color::Red);
shape3.setSize({200, 200});
Canevas canevas2;
canevas2.setPosition({50, 50});
canevas2.clipping = {0, 0, 200, 200};
canevas2.drawables.push_back(&shape2);
canevas2.drawables.push_back(&shape3);
/// CANEVAS 2 -> CANEVAS 1 ///
canevas1.drawables.push_back(&canevas2);
while( window.isOpen() )
{
sf::Event event;
while( window.pollEvent(event) )
{
if( event.type == sf::Event::Closed )
window.close();
else if( event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape )
window.close();
}
window.clear();
window.draw(canevas1);
window.display();
}
return 0;
}
La vignette du milieu présente le résultat de l'exemple minimal, celle de gauche est le résultat du clipping désactivé et celle de droite le résultat attendu.
Quelle est d'après-vous la meilleure technique à employer, sachant que je recherche simplicité et performances avant-tout ?
Merci de votre soutien !