Forum de la communauté SFML

Aide => Graphique => Discussion démarrée par: gaulois94 le Juin 29, 2012, 03:57:04 pm

Titre: Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 03:57:04 pm
Bonjours,

voila je poste ici pour dire que un sf::Image n'arrive pas à se détruire lorsque l'un de ses pixels soit transparent avec une image derrière. Je m'explique : Je déplace ma Windows comme ceci :
        guiml::Window window(sf::VideoMode(800, 600), std::string("teste"), NULL, 60, sf::Color::Black, guiml::Image(NULL, std::string("background.jpg")));

Je pense qu'il y a pas besoin de commenter mais je le fait : je créer une Windows de taille 800,600, de titre "teste" qui n'a pas de parent, avec un framerate de 60, une couleur noir pour le clean et une image en fond d'écran qui est background.jpg.

Mais la je rencontre un tout petit (gros ?) problème. Si déclare un sf::Sprite et que je souhaite que l'un de ses pixels soit transparent, je rencontre (grâce à gdb) l'erreur suivante :

(gdb) where
#0  0x00007ffff678e2c5 in _int_free () from /lib/libc.so.6
#1  0x00007ffff7bbcee0 in __gnu_cxx::new_allocator<unsigned char>::deallocate(unsigned char*, unsigned long) () from ../../lib/libGUIML.so
#2  0x00007ffff7bbce8e in std::_Vector_base<unsigned char, std::allocator<unsigned char> >::_M_deallocate(unsigned char*, unsigned long) () from ../../lib/libGUIML.so
#3  0x00007ffff7bbcddb in std::_Vector_base<unsigned char, std::allocator<unsigned char> >::~_Vector_base() () from ../../lib/libGUIML.so
#4  0x00007ffff7bbcd1d in std::vector<unsigned char, std::allocator<unsigned char> >::~vector() () from ../../lib/libGUIML.so
#5  0x00007ffff7bbcc3e in sf::Image::~Image() () from ../../lib/libGUIML.so
#6  0x00007ffff7bbb347 in guiml::Image::roundEdge(int) () from ../../lib/libGUIML.so
#7  0x000000000040119d in main ()

Je pense que la fonction roundEdge vous sera utile, d'ailleurs la voici :

void Image::roundEdge(int size)
        {
                if(m_sprite.getTexture())
                {
                        sf::Image image = m_sprite.getTexture()->copyToImage();

                        for(int i = 0; i != size; i++)
                        {
                                sf::Vector2f topleft = circle(i, size, size, size);
                                sf::Vector2f bottomleft = circle(i, size, m_sprite.getTexture()->getSize().y - size, size);

                                sf::Vector2f topright = circle(i + m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().x - size, size, size);
                                sf::Vector2f bottomright = circle(i + m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().y - size, size);

                                for(int j = 0; j < topleft.y; j++)
                                {
                                        sf::Color pixel = image.getPixel(i, j);
                                        pixel.a = 0;
                                        image.setPixel(i, j, pixel);
                                }

                                for(int j = m_sprite.getTexture()->getSize().y; j > bottomleft.x; j--)
                                {
                                        sf::Color pixel = image.getPixel(i, j);
                                        pixel.a = 0;
                                        image.setPixel(i, j, pixel);
                                }

                                for(int j = 0; j < topright.y; j++)
                                {
                                        sf::Color pixel = image.getPixel(i + m_sprite.getTexture()->getSize().x - size, j);
                                        pixel.a = 0;
                                        image.setPixel(i + m_sprite.getTexture()->getSize().x - size, j, pixel);
                                }

                                for(int j = m_sprite.getTexture()->getSize().y ; j > bottomright.x; j--)
                                {
                                        sf::Color pixel = image.getPixel(i + m_sprite.getTexture()->getSize().x - size, j);
                                        pixel.a = 0;
                                        image.setPixel(i + m_sprite.getTexture()->getSize().x - size, j, pixel);
                                }
                        }
                        setImage(image);
                }
        }
 

et voici la fonction circle :

sf::Vector2f circle(const float x, const float centerx, const float centery, const float size)
{
        float y1 = (2*centery + sqrt(4*(-(x-centerx)*(x-centerx)+size*size)))/2;
        float y2 = (2*centery - sqrt(4*(-(x-centerx)*(x-centerx)+size*size)))/2;
        return sf::Vector2f(y1, y2);
}

Je pense que le tout est assez clair :D . Je vous remercie beaucoup ;) . Si vous ne comprenez pas un bout de code (ce qui risque d'arriver), n'hésitez pas ;) .
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: Laurent le Juin 29, 2012, 04:33:09 pm
C'est surtout la fonction setImage qu'il faudrait voir.
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 04:40:05 pm
La voici :

void Image::setImage(const sf::Image &image)
        {
                try
                {
                        if(!(m_texture.loadFromImage(image)))
                                throw std::string ("The image is invalid");
                }

                catch(const std::string &error)
                {
                        std::cerr << error << std::endl;
                }

                m_sprite.setTexture(m_texture);
                setRect(getVirtualRect()); //remettre le sprite à la position et taille donné avant le setImage.
        }
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: Laurent le Juin 29, 2012, 05:21:18 pm
Là je ne vois pas. Il faudrait que tu essayes de reproduire l'erreur dans un code complet minimal.

A part ça, quel est l'intérêt de jeter une exception pour l'attraper aussitôt, dans la même fonction ?
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 05:27:03 pm
J'en sais moi même rien pourquoi j'ai mis l'exception x) un std::cout << aurait suffit...

Le soucis est que le code plante uniquement quand j'ai un background (si le fond est noir, j'ai pas de soucis...). Es-ce dû aux caractère jpg des images ?
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: Laurent le Juin 29, 2012, 08:02:42 pm
Citer
Es-ce dû aux caractère jpg des images ?
Non.

Sans code complet minimal on n'arrivera à rien, alors... au boulot ;)
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 09:11:32 pm
Très bien très bien je m'y mes :p (moi qui suis fegnant :p ). (je revient dans 1h alors :p ).
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 09:32:03 pm
Vous allez rire, mais mon code minimal lui fonctionne, alors que mon gros code lui ne fonctionne pas :p . Voici le code minimal quand même :

#include <SFML/Graphics.hpp>
#include <iostream>
#include <algorithm>
#include "equation.h"

void roundEdge(sf::Sprite& m_sprite, sf::Texture& m_texture, int size);

int main()
{
        sf::RenderWindow window(sf::VideoMode(800, 600, 32), std::string("teste"));
       
        sf::Texture backgroundTexture;
        backgroundTexture.loadFromFile("background.jpg");
        sf::Sprite backgroundSprite(backgroundTexture);
        backgroundSprite.setScale(window.getSize().x/backgroundSprite.getLocalBounds().width, window.getSize().y/backgroundSprite.getLocalBounds().height);

        sf::Texture rectangleTexture;
        rectangleTexture.loadFromFile("rectangle.jpg");
        sf::Sprite rectangleSprite(rectangleTexture);
        roundEdge(rectangleSprite, rectangleTexture, 10);

        while(window.isOpen())
        {
                window.clear();
                window.draw(backgroundSprite);
                window.draw(rectangleSprite);
                window.display();
        }
}


void roundEdge(sf::Sprite& m_sprite, sf::Texture& m_texture, int size)
{
        if(m_sprite.getTexture())
        {
                sf::Image image = m_sprite.getTexture()->copyToImage();
                for(int i = 0; i != size; i++)
                {
                        sf::Vector2f topleft = circle(i, size, size, size);
                        sf::Vector2f bottomleft = circle(i, size, m_sprite.getTexture()->getSize().y - size, size);

                        sf::Vector2f topright = circle(i + m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().x - size, size, size);
                        sf::Vector2f bottomright = circle(i + m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().x - size, m_sprite.getTexture()->getSize().y - size, size);

                        for(int j = 0; j < topleft.y; j++)
                        {
                                sf::Color pixel = image.getPixel(i, j);
                                pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-size)*(i-size) + (j-size)*(j-size)))-size+1)/2.f)), 1.f), 0.f));
                                image.setPixel(i, j, pixel);
                        }

                        for(int j = m_sprite.getTexture()->getSize().y; j > bottomleft.x; j--)
                        {
                                sf::Color pixel = image.getPixel(i, j);
                                pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-size)*(i-size) + (j-(m_sprite.getTexture()->getSize().y - size))*(j-(m_sprite.getTexture()->getSize().y - size))))-size+1)/2.f)), 1.f), 0.f));
                                image.setPixel(i, j, pixel);
                        }

                        for(int j = 0; j < topright.y; j++)
                        {
                                sf::Color pixel = image.getPixel(i + m_sprite.getTexture()->getSize().x - size, j);
                                pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-(m_sprite.getTexture()->getSize().x - size))*(i-(m_sprite.getTexture()->getSize().x - size)) + (j-size)*(j-size)))-size+1)/2.f)), 1.f), 0.f));
                                image.setPixel(i + m_sprite.getTexture()->getSize().x - size, j, pixel);
                        }

                        for(int j = m_sprite.getTexture()->getSize().y ; j > bottomright.x; j--)
                        {
                                sf::Color pixel = image.getPixel(i + m_sprite.getTexture()->getSize().x - size, j);
                                pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-(m_sprite.getTexture()->getSize().x - size))*(i-(m_sprite.getTexture()->getSize().x - size)) + (j-(m_sprite.getTexture()->getSize().y - size))*(j-(m_sprite.getTexture()->getSize().y - size))))-size+1)/2.f)), 1.f), 0.f));
                                image.setPixel(i + m_sprite.getTexture()->getSize().x - size, j, pixel);
                        }
                }

                m_texture.loadFromImage(image);
                m_sprite.setTexture(m_texture);
                m_sprite.setScale(m_sprite.getGlobalBounds().width/m_sprite.getLocalBounds().width, m_sprite.getGlobalBounds().height/m_sprite.getLocalBounds().height);
                m_sprite.setPosition(0, 0);
        }
}
 

Je ne comprends pas, j'ai exactement copié la fonction comme elle est, sauf que j'ai intégré à l'intérieur setImage... sa me fait peur dit donc x) .


édit : voici avec le code d'origine l'erreur que j'ai : *** glibc detected *** ./bin/test: corrupted double-linked list: 0x000000000271e5e0 ***
édit 2 : après des teste, l'erreur vient à la fin de la fonction roundEdge (j'ai fait std::cout << 1 << std::endl; et décommenter le setImage pour en être sûr). Je ne sais donc pas d'où vient l'erreur....
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: Laurent le Juin 29, 2012, 10:32:57 pm
C'est aussi à cela que sert le code minimal, à se rendre compte de certaines choses et avancer. Ca s'appelle aussi debugger -- non, debugger ce n'est pas juste appuyer sur F5 dans l'EDI ;)

En gros il faut que tu continues à creuser, que tu testes d'autres morceaux de code, etc. Petit à petit tu vas converger vers le bug. C'est ce que je fais toujours quand j'ai un bug, c'est ce que font la plupart des développeurs.

Sur les forums on peut aider sur les problèmes typiques, mais sur des erreurs complexes comme ça, qui ne se produisent que dans leur contexte original... y a pas grand chose de plus à faire, il n'y a que toi qui puisse avancer sur le problème.
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 29, 2012, 10:55:54 pm
Ben vu l'erreur générer par gdb, je pensais à la base que sa venait de sf::Image, et non de moi. Je ne comprends décidément pas cette erreur qui est dû à une destruction de sf::Image... Je vais essayer de creuser, mais sa ne va pas être très simple x) .

Juste pour savoir, es-ce que le fait d'éditer un pixel dans sf::Image qui sort de son cadre pour gérer une erreur de ce type ?

édit : j'ai trouver l'origine du bug, mais il faudra m'expliquer un petit paradoxe ;) . Voila le bug était (si je comprends la manière dont je les résolues) que je prenait un pixel en trop sur l'axe y pour les arrondies du bas. J'ai donc ceci maintenant :

        for(int j = m_sprite.getTexture()->getSize().y-1; j > bottomleft.x; j--) //deuxième boucle for du code d'origine. Remarquer le -1 à l'initialisation de j
                                {
                                        sf::Color pixel = image.getPixel(i, j);
                                        pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-size)*(i-size) + (j-(m_sprite.getTexture()->getSize().y - size))*(j-(m_sprite.getTexture()->getSize().y - size))))-size+1)/2.f)), 1.f), 0.f));
                                        image.setPixel(i, j, pixel);
                                }

for(int j = m_sprite.getTexture()->getSize().y -1; j > bottomright.x; j--) //dernière boucle for du code d'origine. Encore un -1 à l'initialisation de j
                                {
                                        sf::Color pixel = image.getPixel(i + m_sprite.getTexture()->getSize().x - size, j);
                                        pixel.a = 255 * (1.f - std::max(std::min((float((sqrt((float)((i-(m_sprite.getTexture()->getSize().x - size))*(i-(m_sprite.getTexture()->getSize().x - size)) + (j-(m_sprite.getTexture()->getSize().y - size))*(j-(m_sprite.getTexture()->getSize().y - size))))-size+1)/2.f)), 1.f), 0.f));
                                        image.setPixel(i + m_sprite.getTexture()->getSize().x - size, j, pixel);
                                }

C'est beaux, sa marche, mais pourquoi l'erreur n'a pas surgit avec le code minimal ? Qu'es-ce qui peut bien changer entre les deux ? Là franchement il faudra m'expliquer ;) .
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: Laurent le Juin 30, 2012, 08:56:38 am
Un dépassement de tableau provoque un comportement indéterminé. Et ça, comme son nom l'indique, ça peut se manifester de moultes façons... ou pas ;)
Titre: Re : Problème de transparence sf::Image lorsque j'ai une image en background
Posté par: gaulois94 le Juin 30, 2012, 01:31:06 pm
D'accord :) (j'aurai quand même penser que, vu le nombre de fois où j'ai lancé le programme sans background que j'aurai pu tomber sur cette erreur, mais non je n'y suis jamais tombé :) ). Merci encore :D