Forum de la communauté SFML

Aide => Graphique => Discussion démarrée par: Dragonic le Mai 08, 2013, 07:39:04 pm

Titre: [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 08, 2013, 07:39:04 pm
Bonjour à tous déjà ^^ !

Alors voilà, je cherche à utiliser des images de type NinePatch, pour avoir des images redimensionnées sans déformer les bords !
Si vous ne savez pas ce qu'est le 9-slice scaling, l'image ci-dessous résume parfaitement la situation ^^ :

(http://99designs.com/designer-blog/wp-content/uploads/2012/08/07-nine-slice.png)

En gros c'est donc une méthode pour "bloquer" le redimensionnement des bords.

Enfin bref, j'étais donc en train de concevoir ma petite classe qui allait faire le découpage de l'image source vers l'image redimensionnée correctement. Dans l'ordre j'ai donc :
- charger l'image source dans une sf::Image
- découper cette image en 9 subImage (aussi de type sf::Image) à coup de copy(sf::IntRect);

Et là je souhaitais donc refaire une image de la taille souhaitée, dans laquelle j'aurais mis mes subImages morceau par morceau, et redimensionnées comme il faut !

Je fais quelques recherches, et la seule façon que je trouve pour faire ça c'est d'utiliser :
- un sf::RenderImage dans lequel on va dessiner
- des sprites pour redimensionner avec sf::Sprite.resize(p_width, p_height)
(vu entre autre sur ce topic : http://en.sfml-dev.org/forums/index.php?topic=4119.0 )

Oui mais voilà, RenderImage pour moi ça n'existe tout simplement pas ><, de même que la fonction resize() de sf::Sprite ! Je ne comprend pas trop. Je croise plein de topic concernant SFML 2.0 indiquants l'utilisation de sf::RenderImage, mais j'aimerais bien comprendre comment on est sensé utiliser un truc qui n'est pas dans la SFML 2.0 >< ( http://www.sfml-dev.org/documentation/2.0/classes.php ou http://www.sfml-dev.org/documentation/2.0/files.php ) ! De même donc pour la fonction resize() de sf::Sprite, j'aimerais qu'on m'explique là >< !

Enfin bref, ça me permet entre autre aussi de vous demander quelle est la meilleur façon de faire ma petite opération de découpage/redimensionnement vu que pour l'instant je suis donc bloqué ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Laurent le Mai 08, 2013, 07:59:56 pm
SFML 2.0 ne s'est pas faite en un jour, elle a évolué depuis plusieurs années, des choses ont été ajoutées, d'autres renommées ou encore supprimées. Regarde la date des posts que tu lis sur le forum, et si c'est vieux, ne sois pas étonné que ça ne corresponde pas à ce que SFML 2.0 en version finale est aujourd'hui.

Ensuite concernant ton problème, tu t'embêtes pour pas grand chose. Charge ton image dans un sf::Texture, puis crée 9 sprites utilisant cette texture, avec chacun un textureRect correspondant à l'une des 9 parties du découpage. Puis dessines ces 9 sprites côté à côté, en étirant (setScale) ceux qu'il faut dans la direction qu'il faut.

PS : lis d'abord les tutos et la doc pour te mettre à jour sur l'API :P
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 08, 2013, 08:05:45 pm
Merci pour la réponse rapide Laurent ^^ !

Je me doutais bien que les specs de la SFML 2 avaient évolués avec le temps, mais de voir de telles différences sur une version arrêtée (2.0) de la lib je trouve ça vraiment bizarre ^^ !
De ce dire d'un côté "tu peux utiliser sf::RenderImage avec SFML 2.0", mais qu'en fait c'est plus possible bien qu'on soit toujours en SFML 2.0, c'est assez déroutant !

J'ai relu les tutos, mais ça ne présentait pas vraiment la façon de décomposer une image et de la redimensionner, ni même de blitter une image sur une autre !

Quoi qu'il en soit, merci pour les détails de la manip à faire, je m'y mets de suite, et viendrai présenter le résultat !

P.S. : j'avais vu le setScale() dans sf::Sprite ! Cela m’inquiète peut être un peu de ne pas être assurée (ou de ne pas comprendre ^^) de la taille finale après le scaling ! En prenant un exemple, une sprite 25x25 à laquelle on applique un scale(0.5, 0.5), ça produis quoi ? 12x12 ou 13x13 ?
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Eroy le Mai 08, 2013, 08:25:06 pm
12.5x12.5, les bounds sont en float.

Là pour le coup un renderTexture pourrait être assez sympa pour gérer le 9, non ? Ca me donne des idées...
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 08, 2013, 08:50:04 pm
12.5x12.5, les bounds sont en float.

Là pour le coup un renderTexture pourrait être assez sympa pour gérer le 9, non ? Ca me donne des idées...

Comment se passe le rendu avec ce genre de situation ?
Je veux dire, quand on fait window.draw(sprite); et que celui-ci fait donc 12.5x12.5, on peut pas s'amuser bien sûr à dessiner que sur un demi-pixel ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Eroy le Mai 08, 2013, 10:05:13 pm
Ben tu pourras par exemple avoir un pixel avec une transparence de 0.5.
Mais surtout ya plusieurs paramètres qui rentres en compte, ne serait-ce que la vue. Si ta texture est affichée dans une vue qui fait un zoom*2 alors ton demi-pixel apparaîtra comme 1 pixel. Je pense aussi que l'anti-aliasing a une influence là dessus mais j'en suis pas certain.
Titre: Re : Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 08, 2013, 11:50:59 pm
Ben tu pourras par exemple avoir un pixel avec une transparence de 0.5.
Mais surtout ya plusieurs paramètres qui rentres en compte, ne serait-ce que la vue. Si ta texture est affichée dans une vue qui fait un zoom*2 alors ton demi-pixel apparaîtra comme 1 pixel. Je pense aussi que l'anti-aliasing a une influence là dessus mais j'en suis pas certain.

Le fait que l'effet change sur ce pixel en fonction de paramètres n'est pas ultra rassurant de mon côté  ! Mais bon je vais appliquer ce que j'ai et je m'adapterais ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Eroy le Mai 09, 2013, 12:50:02 am
Je pense que si tu ne mets pas de smooth sur les textures ya des chances que ça ne le fasse pas... Enfin je sais pas trop quoi j'ai pas vraiment regardé en général c'est plutôt bien fait et ça passe inaperçu. C'est surtout pour les shapes en fait que c'est visible en général quand tu mets un bord noir.
Mais en même temps le scale c'est pas fait pour être ultra-précis, si tu veux créer une texture (là en l'occurrence je pense que c'est ce que tu veux avec les 9) tu devrais la créer réellement comme ça t'es certain du rendu, se sera même plus performant, sauf si vraiment t'en crée énormément et dans ce cas tu y perdrais en ram mais bon...
Mais sinon les assembler avec scale ne pose aucun problème de troue de 1px entre deux sprites (entre par exemple le milieu scalé et le coin), en tout cas chez moi c'est bon.
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 09, 2013, 01:17:11 am
Pour l'instant j'ai juste fait le découpage en 9 sprites, et une fonction qui affiche alors le résultat à la taille souhaitée, en blittant sprite par sprite !
Tout marche bien à ce niveau, le 9-slice scaling est correct !

Je suis en train de faire la fonction qui renvoi directement une texture, provenant d'une sf::RenderTexture, dans laquelle j'aurais blitter les sprites à la bonne taille, dans le cas d'une ressource qui n'a pas besoin d'être redimensionnée plus !

EDIT : outre le fait que la texture est inversée en passant par la fonction retournant la texture d'un RenderTexture, tout fonctionne bien.
Titre: Re : Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: G. le Mai 09, 2013, 03:21:17 am
EDIT : outre le fait que la texture est inversée en passant par la fonction retournant la texture d'un RenderTexture, tout fonctionne bien.
display (http://www.sfml-dev.org/documentation/2.0-fr/classsf_1_1RenderTexture.php#af92886d5faef3916caff9fa9ab32c555) ?
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Eroy le Mai 09, 2013, 08:57:33 am
Oui là t'as oublié le display. x)
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Laurent le Mai 09, 2013, 09:06:55 am
Citer
Je me doutais bien que les specs de la SFML 2 avaient évolués avec le temps, mais de voir de telles différences sur une version arrêtée (2.0) de la lib je trouve ça vraiment bizarre ^^ !
De ce dire d'un côté "tu peux utiliser sf::RenderImage avec SFML 2.0", mais qu'en fait c'est plus possible bien qu'on soit toujours en SFML 2.0, c'est assez déroutant !
SFML 2.0 n'est sortie qu'il y a 10 jours. Avant ça, ce n'était pas SFML 2.0, c'était plutôt "le gros chantier qui mène à SFML 2". Il n'y a jamais eu de release officielle (à part la RC), les gens utilisaient toujours les dernières sources directement.

Bref, sinon pour le reste les autres ont répondu ;)
Titre: Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 09, 2013, 11:51:53 am
Merci pour les réponses Eroy, G. et pour les détails Laurent !

Voici donc les sources de cette classe NinePatch que je viens de créer pou gérer ces images, que je dois donc maintenant optimiser un peu ( notamment pour gérer les zoom <1 ) :

NinePatch.h
/*
 * NinePatch.h
 *
 *  Created on: 8 mai 2013
 *      Author: Dragonic
 */


#ifndef NINEPATCH_H_
#define NINEPATCH_H_

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>

class NinePatch
{
public:
        NinePatch(std::string url);

        void draw(sf::Vector2f pos, sf::Vector2f size, sf::RenderWindow &window);
        sf::Texture getTextureResize(sf::Vector2f size);

        sf::Texture getSourceTexture()
        {
                sf::IntRect rect=sf::IntRect(1, 1, m_width, m_height);
                sf::Sprite sprite=sf::Sprite(m_texture, rect);
                return *sprite.getTexture();
        }

        sf::Texture getSourceTextureFull()
        {
                return m_texture;
        }

protected:
private:
        sf::Sprite m_subImages[9];
        sf::Texture m_texture;
        sf::IntRect m_rect[9];
        unsigned int m_width;
        unsigned int m_height;
};


#endif /* NINEPATCH_H_ */
 


NinePatch.cpp
/*
 * NinePatch.cpp
 *
 *  Created on: 9 mai 2013
 *      Author: Dragonic
 */


#include "NinePatch.h"

NinePatch::NinePatch(std::string url)
{
        sf::Image image;

        if (!image.loadFromFile(url))
        {
                std::cout<<"error chargement image NinePatch"<<std::endl;
        }

        m_texture.loadFromImage(image);


        unsigned int w=image.getSize().x;
        unsigned int h=image.getSize().y;
        m_width = w-2;
        m_height = h-2;

        unsigned int x1=0;
        unsigned int y1=0;
        unsigned int x2=w-1;
        unsigned int y2=h-1;

        while((image.getPixel(x1, 0)) != sf::Color::Black)//on cherche le 1er pixel non transparent
        {
                x1++;
        }

        if(x1!=x2)
        {
                while((image.getPixel(x2, 0)) != sf::Color::Black)
                {
                                x2--;
                }
        }

        while((image.getPixel(0, y1)) != sf::Color::Black)
        {
                y1++;
        }

        if(y1!=y2)
        {
                while((image.getPixel(0, y2)) != sf::Color::Black)
                {
                                y2--;
                }
        }

        if(x1==x2 && y1==y2)//aucune ligne trouvé
        {
                std::cout<<"error NinePatch non configuré"<<std::endl;
        }

        m_rect[0]=sf::IntRect(1, 1, x1, y1);
        m_subImages[0]=sf::Sprite(m_texture, m_rect[0]);

        m_rect[1]=sf::IntRect(1+x1, 1, x2-x1-1, y1);
        m_subImages[1]=sf::Sprite(m_texture, m_rect[1]);

        m_rect[2]=sf::IntRect(1+x2, 1, w-x2-2, y1);
        m_subImages[2]=sf::Sprite(m_texture, m_rect[2]);

        m_rect[3]=sf::IntRect(1, 1+y1, x1, y2-y1);
        m_subImages[3]=sf::Sprite(m_texture, m_rect[3]);

        m_rect[4]=sf::IntRect(1+x1, 1+y1, x2-x1-1, y2-y1);
        m_subImages[4]=sf::Sprite(m_texture, m_rect[4]);

        m_rect[5]=sf::IntRect(1+x2, 1+y1, w-x2-2, y2-y1);
        m_subImages[5]=sf::Sprite(m_texture, m_rect[5]);

        m_rect[6]=sf::IntRect(1, 1+y2, x1, h-y2-2);
        m_subImages[6]=sf::Sprite(m_texture, m_rect[6]);

        m_rect[7]=sf::IntRect(1+x1, 1+y2, x2-x1-1, h-y2-2);
        m_subImages[7]=sf::Sprite(m_texture, m_rect[7]);

        m_rect[8]=sf::IntRect(1+x2, 1+y2, w-x2-2, h-y2-2);
        m_subImages[8]=sf::Sprite(m_texture, m_rect[8]);

};

void NinePatch::draw(sf::Vector2f pos, sf::Vector2f size, sf::RenderWindow &window)
{
        float wScale = (size.x - m_rect[0].width - m_rect[2].width) / m_rect[1].width;
        float hScale = (size.y - m_rect[0].height - m_rect[6].height) / m_rect[3].height;

        sf::Sprite subImages[9];
        for(int i=0;i<9;i++)
        {
                subImages[i]=m_subImages[i];
        }

        subImages[0].setPosition(pos);
        window.draw(subImages[0]);

        subImages[1].setPosition(pos.x+m_rect[0].width, pos.y);
        subImages[1].setScale(wScale,1);
        window.draw(subImages[1]);

        subImages[2].setPosition(pos.x+m_rect[0].width+m_rect[1].width*wScale, pos.y);
        window.draw(subImages[2]);

        subImages[3].setPosition(pos.x, pos.y+m_rect[0].height);
        subImages[3].setScale(1,hScale);
        window.draw(subImages[3]);

        subImages[4].setPosition(pos.x+m_rect[3].width, pos.y+m_rect[1].height);
        subImages[4].setScale(wScale,hScale);
        window.draw(subImages[4]);

        subImages[5].setPosition(pos.x+m_rect[3].width+m_rect[4].width*wScale, pos.y+m_rect[2].height);
        subImages[5].setScale(1,hScale);
        window.draw(subImages[5]);

        subImages[6].setPosition(pos.x, pos.y+m_rect[0].height+m_rect[3].height*hScale);
        window.draw(subImages[6]);

        subImages[7].setPosition(pos.x+m_rect[6].width, pos.y+m_rect[1].height+m_rect[4].height*hScale);
        subImages[7].setScale(wScale,1);
        window.draw(subImages[7]);

        subImages[8].setPosition(pos.x+m_rect[6].width+m_rect[7].width*wScale, pos.y+m_rect[2].height+m_rect[5].height*hScale);
        window.draw(subImages[8]);
}

sf::Texture NinePatch::getTextureResize(sf::Vector2f size)
{
        float wScale = (size.x - m_rect[0].width - m_rect[2].width) / m_rect[1].width;
        float hScale = (size.y - m_rect[0].height - m_rect[6].height) / m_rect[3].height;

        sf::Sprite subImages[9];
        for(int i=0;i<9;i++)
        {
                subImages[i]=m_subImages[i];
        }

        sf::RenderTexture renderTexture;
        renderTexture.create(size.x,size.y);
        renderTexture.clear(sf::Color::Transparent);

        subImages[0].setPosition(0,0);
        renderTexture.draw(subImages[0]);

        subImages[1].setPosition(0+m_rect[0].width, 0);
        subImages[1].setScale(wScale,1);
        renderTexture.draw(subImages[1]);

        subImages[2].setPosition(0+m_rect[0].width+m_rect[1].width*wScale, 0);
        renderTexture.draw(subImages[2]);

        subImages[3].setPosition(0, 0+m_rect[0].height);
        subImages[3].setScale(1,hScale);
        renderTexture.draw(subImages[3]);

        subImages[4].setPosition(0+m_rect[3].width, 0+m_rect[1].height);
        subImages[4].setScale(wScale,hScale);
        renderTexture.draw(subImages[4]);

        subImages[5].setPosition(0+m_rect[3].width+m_rect[4].width*wScale, 0+m_rect[2].height);
        subImages[5].setScale(1,hScale);
        renderTexture.draw(subImages[5]);

        subImages[6].setPosition(0, 0+m_rect[0].height+m_rect[3].height*hScale);
        renderTexture.draw(subImages[6]);

        subImages[7].setPosition(0+m_rect[6].width, 0+m_rect[1].height+m_rect[4].height*hScale);
        subImages[7].setScale(wScale,1);
        renderTexture.draw(subImages[7]);

        subImages[8].setPosition(0+m_rect[6].width+m_rect[7].width*wScale, 0+m_rect[2].height+m_rect[5].height*hScale);
        renderTexture.draw(subImages[8]);

        renderTexture.display();

        return renderTexture.getTexture();
}

 


Et un exemple d'utilisation :
window.clear(sf::Color::White);
        NinePatch ninePatch("resources/btn.9.png");
        ninePatch.draw(sf::Vector2f(200,200),sf::Vector2f(200,100),window);

        sf::Sprite sprite2;
        sf::Texture texture2;
        texture2 = ninePatch.getTextureResize(sf::Vector2f(100,300));
        sprite2.setTexture(texture2);
        sprite2.setPosition(50,10);
        window.draw(sprite2);

        sf::Sprite sprite3;
        sf::Texture texture3;
        texture3 = ninePatch.getSourceTexture();
        sprite3.setTexture(texture3);
        sprite3.setPosition(200,10);
        window.draw(sprite3);

        sf::Sprite sprite4;
        sf::Texture texture4;
        texture4 = ninePatch.getSourceTextureFull();
        sprite4.setTexture(texture4);
        sprite4.setPosition(350,10);
        window.draw(sprite4);


ce code fourni le résultat suivant :
(http://image.noelshack.com/fichiers/2013/19/1368092765-sans-titre.jpg)


Et si vous voulez l'image source btn.9.png :
(http://image.noelshack.com/fichiers/2013/19/1368092868-btn-9.png)



Alors ce qu'il faut savoir, c'est qu'une image de type NinePatch, c'est une image avec une ligne de pixel en plus de chaque côté pour définir les règles de redimensionnement et de contenu. En haut et à gauche les traits noirs définissent les zones ayant le droit d'être redimensionnées.

Je n'ai pas encore rajouter la fonctionnalité pour les lignes à mettre à droite et en bas, qui définissent la zone de contenu, bien pratique pour ensuite placer des éléments (texte ou autre) dans la texture redimensionnée. Néanmoins donc il faut bien rajouter une ligne de pixel à droite et en bas quand même par défaut pour que le NinePatch soit correct.

Enfin bref, pour l'instant les résultats produits me suffisent ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - [Résolu / code source dispo]
Posté par: Laurent le Mai 09, 2013, 02:01:53 pm
Citer
    sf::Texture getSourceTexture()
    {
        sf::IntRect rect=sf::IntRect(1, 1, m_width, m_height);
        sf::Sprite sprite=sf::Sprite(m_texture, rect);
        return *sprite.getTexture();
    }
Cette fonction ne sert strictement à rien, quoique tu fasses à ton sprite, sa texture ne sera jamais modifiée.

Sinon, pourquoi dupliquer tout le code de draw dans getTextureResize ? Si draw prenait un sf::RenderTarget& plutôt qu'un sf::RenderWindow&, tu pourrais appeler draw dans getTextureResize en passant ta RenderTexture. Et du coup cette dernière fonction ne ferait plus que 3 lignes de code.

Pourquoi faire une copie de tes 9 sprites à chaque fois ? Ca me paraît inutile par rapport à ce que tu en fais ensuite.

Dans ton exemple : c'est vraiment pas terrible de charger le truc en plein milieu du dessin (ça laisse supposer que tu le fais à chaque fois).

Ensuite, des considérations un peu plus conceptuelles. Déjà, getTextureResize ne me paraît pas utile. Ca sert à quoi de recréer de toute pièce une nouvelle texture avec l'image finale du truc étiré, alors que tu as déjà une fonction qui peut dessiner un même NinePatch à n'importe quelle taille sans que ce soit trop coûteux ?

Bon, on peut se dire que tu veuilles économiser un maximum, et pouvoir dessiner un NinePatch en 1 appel à draw (interne) plutôt que 9. C'est pas idiot. Mais dans ce cas, utilise un vertex array plutôt que 9 sprites : tu pourras le dessiner en un seul appel, tout en gardant la flexibilité de pouvoir choisir la taille dynamiquement.

Ensuite... moi je ferais ça pour vraiment optimiser l'utilisation des ressources :

class NinePatchTexture
{
public:
    bool loadFromFile(const std::string&);

private:
    friend class NinePatchSprite;
    enum Area {TopLeft, Top, TopRight, ... };
    sf::Texture& getTexture();
    sf::IntRect getRect(Area area);
};

class NinePatchSprite : public sf::Transformable, public sf::Drawable // cf. les tutos
{
public:
    void setTexture(const NinePatchTexture& texture);
    void setSize(sf::Vector2f size);

private:
    void draw(sf::RenderTarget& target, sf::RenderStates states) const;
    NinePatchTexture* m_texture;
    sf::Vertex vertices[36];
}

NinePatchTexture texture;
texture.loadFromFile("...");

NinePatchSprite button1;
button1.setTexture(texture);
button1.setSize(sf::Vector2f(100, 50));

NinePatchSprite button2;
button2.setTexture(texture);
button2.setSize(sf::Vector2f(200, 100));

...

window.draw(button1);
window.draw(button2);
Titre: Re : [SFML 2.0] 9-slice scaling - [Résolu / code source dispo]
Posté par: Dragonic le Mai 09, 2013, 02:24:23 pm
Merci Laurent !

Si j'ai passé mon code source, c'est en partie justement pour avoir des retours d'optimisation ^^ !

Pour l'exemple, en effet ça sert à rien de recharger à chaque fois ^^ ! C'était simplement pour donner un exemple sans avoir à mettre tout le code de la boucle ^^ !

RenderTarget je ne connaissais pas forcément, mais en effet ça simplifie les choses de passer par cette classe mère !

le getTextureResize est là car en effet je me demandais à quel point c'était coûteux ou non de refaire le redimensionnement des 9 sprites et les blitter à chaque frame, plutôt que d'avoir une texture fixe, finie, que j'aurais donc pas à redimensionner, et nécessitant qu'un draw ^^ ! Ça me coûtait rien de plus de faire ça ^^ !

Après, je n'ai pas encore pris connaissance des sf::Vertex, ni les VertexArray. Je vais devoir regarder ça plus en détail pour comprendre ^^ !

Merci en tout cas pour tes précisions !
Titre: Re : [SFML 2.0] 9-slice scaling - [Résolu / code source dispo]
Posté par: Laurent le Mai 09, 2013, 02:33:04 pm
Citer
le getTextureResize est là car en effet je me demandais à quel point c'était coûteux ou non de refaire le redimensionnement des 9 sprites et les blitter à chaque frame
Le redimensionnement : c'est quasiment gratos.
Le dessin : si tu n'as que quelques NinePatch ça ne va pas changer la face du monde ; maintenant, si tu commences à en avoir quelques centaines ou milliers, là ça vaut le coup de réduire le nombre d'appels internes à draw.

Note que le terme "blitter" est préhistorique (et, accessoirement, n'existe pas en français), il fait référence à une technique complètement désuète : "coller" les pixels un à un pour dessiner quelque chose. Tu devrais prendre l'habitude de ne plus l'utiliser, sinon tu vas passer pour un vieux sur les forums ;D
Titre: Re : Re : [SFML 2.0] 9-slice scaling - [Résolu / code source dispo]
Posté par: Dragonic le Mai 09, 2013, 02:45:28 pm
Note que le terme "blitter" est préhistorique (et, accessoirement, n'existe pas en français), il fait référence à une technique complètement désuète : "coller" les pixels un à un pour dessiner quelque chose. Tu devrais prendre l'habitude de ne plus l'utiliser, sinon tu vas passer pour un vieux sur les forums ;D

Autant pour moi ^^, je vais éviter d'en parler alors ^^ !
Titre: Re : Re : [SFML 2.0] 9-slice scaling - redimensionner et blitter sur sf::Image
Posté par: Dragonic le Mai 11, 2013, 11:34:17 am
Je reviens sur un petit problème que je ne comprends pas bien !
J'ai remarqué après avoir passé mon programme à quelques amis pour tester que certains voyaient le programme planté à un moment précis.
Ayant recherché la ligne de code où ça plantait c'était incompréhensible, car c'était un glDrawElement qui faisait crasher l'appli (celui de ma skybox), et qui n'avait strictement rien à voir au niveau de la manip pour faire crasher. En gros c'est comme si quelquechose avait massacré ma VRAM d'un coup.

Après quelques recherches j'ai remarqué que le souci venait finalement de ma nouvelle classe NinePatch, et plus particulièrement de sa fonction getTextureResize() qui est sensé écrire les données dans un RenderTexture et me renvoyer la texture correspondante à la fin des draw.


NinePatch.cpp
sf::Texture NinePatch::getTextureResize(sf::Vector2f size)
{
        float wScale = (size.x - m_rect[0].width - m_rect[2].width) / m_rect[1].width;
        float hScale = (size.y - m_rect[0].height - m_rect[6].height) / m_rect[3].height;

        sf::Sprite subImages[9];
        for(int i=0;i<9;i++)
        {
                subImages[i]=m_subImages[i];
        }

        sf::RenderTexture renderTexture;
        renderTexture.create(size.x,size.y);
        renderTexture.clear(sf::Color::Transparent);

        subImages[0].setPosition(0,0);
        renderTexture.draw(subImages[0]);

        subImages[1].setPosition(0+m_rect[0].width, 0);
        subImages[1].setScale(wScale,1);
        renderTexture.draw(subImages[1]);

        subImages[2].setPosition(0+m_rect[0].width+m_rect[1].width*wScale, 0);
        renderTexture.draw(subImages[2]);

        subImages[3].setPosition(0, 0+m_rect[0].height);
        subImages[3].setScale(1,hScale);
        renderTexture.draw(subImages[3]);

        subImages[4].setPosition(0+m_rect[3].width, 0+m_rect[1].height);
        subImages[4].setScale(wScale,hScale);
        renderTexture.draw(subImages[4]);

        subImages[5].setPosition(0+m_rect[3].width+m_rect[4].width*wScale, 0+m_rect[2].height);
        subImages[5].setScale(1,hScale);
        renderTexture.draw(subImages[5]);

        subImages[6].setPosition(0, 0+m_rect[0].height+m_rect[3].height*hScale);
        renderTexture.draw(subImages[6]);

        subImages[7].setPosition(0+m_rect[6].width, 0+m_rect[1].height+m_rect[4].height*hScale);
        subImages[7].setScale(wScale,1);
        renderTexture.draw(subImages[7]);

        subImages[8].setPosition(0+m_rect[6].width+m_rect[7].width*wScale, 0+m_rect[2].height+m_rect[5].height*hScale);
        renderTexture.draw(subImages[8]);

        renderTexture.display();

        return renderTexture.getTexture();
}

 



Le programme ne plante pas si je commente "renderTexture.create(size.x,size.y);".
Bien sûr en résultat dans ce cas je n'ai rien comme texture finale, mais c'est pour l'instant la meilleure piste que j'ai pour régler ce souci !

Pour information, le code a été testé sur plusieurs PCs, et aux retours de configs de chacun d'entre-eux, la seule information commune aux PCs qui crachent est qu'ils sont équipés de cartes nVidia !

Voilà, je n'arrive pas à comprendre plus et j'aurais besoin d'aide désormais pour résoudre ce petit souci !

Merci d'avance !
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Laurent le Mai 11, 2013, 12:05:20 pm
Ce qui serait génial pour t'aider, c'est un code complet et minimal qui reproduit le problème. Pas tout ton bazarre d'origine, vraiment un code réécrit depuis zéro, qui ne fasse que reproduire le problème et rien d'autre.
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 11, 2013, 12:13:07 pm
Je peux essayer, en espérant que le code minimal suffira en effet !

Mais sinon pour reproduire le problème, il semblerait qu'il suffit simplement d'utiliser la classe NinePatch que j'ai présenté page précédente, de récupérer une texture avec la fonction getTextureResize(), et ensuite plus loin de draw un objet OpenGL (pas confirmé qu'il faille forcément un VAO ou autre). Je reprécise qu'il semblerait que le bug n'apparaisse qu'avec des PCs équipés nVidia.

Je vais essayer de faire un code minimal, ce qui n'est pas forcément si simple vu que le projet actuel compte quelques 50000 lignes de codes ^^ ! Je vais essayer donc de faire un mini-projet à part pour aboutir au résultat.
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Eroy le Mai 11, 2013, 12:18:31 pm
Citer
0+m_rect[0].width
? :o
Titre: Re : Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 11, 2013, 12:22:49 pm
Citer
0+m_rect[0].width
? :o

Cette fonction est en partie un copié-coller d'une autre (draw() : voir page précédente) dans laquelle il y avait un paramètre à la place du "0"! j'ai laissé tel quel pour ne pas oublier vu que j'ai pas commenté mon code encore !
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 11, 2013, 01:00:46 pm
J'ai réussi à créer un code minimal reproduisant le problème :

#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

using namespace std;
using namespace sf;

void createSquare(GLuint &vaoID, GLuint &vboID, GLuint &iboID) {
        float* vertices = new float[12];  // Sommets du carré

        vertices[0] = -0.5; vertices[1] = -0.5; vertices[2] = 0.0; // Coin en bas à gauche
        vertices[3] = -0.5; vertices[4] = 0.5; vertices[5] = 0.0; // Coin en haut à gauche
        vertices[6] = 0.5; vertices[7] = 0.5; vertices[8] = 0.0; // Coin en haut à droite
        vertices[9] = 0.5; vertices[10] = -0.5; vertices[11] = 0.0; // Coin en bas à droite

        GLubyte Indices[] = {
    // Top
    1, 2, 0,
    3, 0, 2
        };

        glGenVertexArrays(1, &vaoID); // Créer le VAO
        glBindVertexArray(vaoID); // Lier le VAO pour l'utiliser

        glGenBuffers(1, &vboID); // Générer le VBO
        glBindBuffer(GL_ARRAY_BUFFER, vboID); // Lier le VBO
        glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Définir la taille, les données et le type du VBO

        glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Définir le pointeur d'attributs des sommets

        glGenBuffers(1, &iboID);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

        glEnableVertexAttribArray(0); // Désactiver le VAO
        glBindVertexArray(0); // Désactiver le VBO

        delete [] vertices; // Supprimer les sommets
}

Texture getTextureFromRenderTexture()
{
    RenderTexture renderTexture;

    if(!(renderTexture.create(50,50)))
                std::cout<<"failed create renderTexture"<<std::endl;

    return renderTexture.getTexture();
}

int main()
{
        RenderWindow window;
        window.create(VideoMode(800, 600), "test bug RenderTexture", Style::Default, ContextSettings(32));
    window.setVerticalSyncEnabled(true);

    GLenum initialisationGLEW( glewInit() );

    if(initialisationGLEW != GLEW_OK)
    {
        cout << "Erreur d'initialisation de GLEW : " << glewGetErrorString(initialisationGLEW) << endl;
    }

    Event event;
    bool running=true;

    unsigned int vaoID; // VAO
    unsigned int vboID; // VBO
    unsigned int iboID; // IBO
    createSquare(vaoID, vboID, iboID);

    Texture texture;

    while (running)
    {
        window.setActive();

        while (window.pollEvent(event))
        {
                if (event.type == Event::Closed)
            {
                // on stoppe le programme
                running = false;
            }
                else if ((event.type == Event::KeyPressed) && (event.key.code == Keyboard::T) )
                        {
                         texture = getTextureFromRenderTexture();
                        }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindVertexArray(vaoID); // Lier le VAO

        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);

        glBindVertexArray(0); // Délier le VAO

        window.display();
    }

    window.close();

    return 0;
}
 

Le programme plante sur mon PC nVidia si j'appuie sur T, au niveau du glDrawElements !
J'ai essayé avec ceci à la place de l'utilisation du VAO :
glBegin(GL_LINES);
  glVertex2i(0,0);glVertex2i(0,1);
  glVertex2i(0,0);glVertex2i(1,0);
  glVertex2i(0,0);glVertex3i(0,0,1);
glEnd();

Et cela ne plante pas lors de l'appuie sur T.

De même, testé à l'instant avec seulement "glDrawArrays(GL_TRIANGLES, 0, 3);" (donc sans me servir de l'IBO), et aucun problème. Il semblerait donc que le bug se limite à l'utilisation de glDrawElements.

Et enfin, autre détail, si  "texture = getTextureFromRenderTexture();" est placé avant la boucle principale il n'y a aucun problème. Mais dès qu'il est dedans (par forcément au sein donc d'une réponse à un Event), le programme plante.

A noter donc que si je commente le "renderTexture.create(50,50)" il n'y a aucun problème ! La cause du problème semble donc venir de là !

Voilà, je peux difficilement faire plus précis ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Laurent le Mai 11, 2013, 01:11:42 pm
1. Lis le tutoriel correspondant (Fenêtre et OpenGL), il te manque les push/popGLStates.

2. Appelle window.setActive après l'appel à getTextureFromRenderTexture : là tu ne sais pas quel contexte est actif, puisque celui qui l'était (la RenderTexture) vient d'être détruit.
Titre: Re : Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 11, 2013, 01:16:04 pm
1. Lis le tutoriel correspondant (Fenêtre et OpenGL), il te manque les push/popGLStates.

2. Appelle window.setActive après l'appel à getTextureFromRenderTexture : là tu ne sais pas quel contexte est actif, puisque celui qui l'était (la RenderTexture) vient d'être détruit.

De mettre le "window.setActive()" après la boucle d'evenement (et donc après l'appel à getTextureFromRenderTexture) corrige en effet le souci !

Pour  push/popGLStates je les ai bien sûr vu dans le tuto, mais je les ai pas mis vu que dans cet exemple je ne draw aucun élément SFML. Sont-ils tout de même obligatoire !

EDIT : en effet j'aurais du faire attention que les  push/popGLStates n'était pas là que pour les draw, car si j'entoure le getTextureFromRenderTexture de ces deux instructions le programme ne plante plus. Faut-il en retenir que strictement tous les éléments du module graphique SFML ne doivent être manipulés qu'à travers push/popGLStates à partir du moment où la RenderWindow est active ?

Et la dernière question, c'est pourquoi ce genre de problème n'est pas retourné sur des PCs équipés de cartes ATI (du moins c'est ce que je constate avec les quelques tests fait par des amis) ?
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Laurent le Mai 11, 2013, 03:32:10 pm
Citer
en effet j'aurais du faire attention que les  push/popGLStates n'était pas là que pour les draw, car si j'entoure le getTextureFromRenderTexture de ces deux instructions le programme ne plante plus. Faut-il en retenir que strictement tous les éléments du module graphique SFML ne doivent être manipulés qu'à travers push/popGLStates à partir du moment où la RenderWindow est active ?
Ben, dans ta fonction, tu fais bien des draw non ? :P

Citer
Et la dernière question, c'est pourquoi ce genre de problème n'est pas retourné sur des PCs équipés de cartes ATI (du moins c'est ce que je constate avec les quelques tests fait par des amis) ?
Faut pas chercher d'explication à ce genre de truc. Qui sait ce que font les drivers graphiques...
Titre: Re : Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Dragonic le Mai 11, 2013, 03:52:00 pm
Citer
en effet j'aurais du faire attention que les  push/popGLStates n'était pas là que pour les draw, car si j'entoure le getTextureFromRenderTexture de ces deux instructions le programme ne plante plus. Faut-il en retenir que strictement tous les éléments du module graphique SFML ne doivent être manipulés qu'à travers push/popGLStates à partir du moment où la RenderWindow est active ?
Ben, dans ta fonction, tu fais bien des draw non ? :P

Oui et non !

Oui en effet avec mes NinePatch je fais des draw ! Mais pour l'exemple de code minimal pour reproduire le problème je ne fais strictement rien de tel dans la fonction getTextureFromRenderTexture ^^ !
Titre: Re : [SFML 2.0] 9-slice scaling - souci de RenderTexture
Posté par: Laurent le Mai 11, 2013, 06:48:36 pm
Effectivement.

Mais dans ce cas de figure il faut aussi appeler ces fonctions ;)