Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Problème de transparence sf::Image lorsque j'ai une image en background  (Lu 4404 fois)

0 Membres et 1 Invité sur ce sujet

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
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 ;) .

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
C'est surtout la fonction setImage qu'il faudrait voir.
Laurent Gomila - SFML developer

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
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.
        }

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
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 ?
Laurent Gomila - SFML developer

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
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 ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Es-ce dû aux caractère jpg des images ?
Non.

Sans code complet minimal on n'arrivera à rien, alors... au boulot ;)
Laurent Gomila - SFML developer

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
Très bien très bien je m'y mes :p (moi qui suis fegnant :p ). (je revient dans 1h alors :p ).

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
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....
« Modifié: Juin 29, 2012, 09:46:29 pm par gaulois94 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
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.
Laurent Gomila - SFML developer

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
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 ;) .
« Modifié: Juin 29, 2012, 11:45:41 pm par gaulois94 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème de transparence sf::Image lorsque j'ai une image en background
« Réponse #10 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 ;)
Laurent Gomila - SFML developer

gaulois94

  • Sr. Member
  • ****
  • Messages: 259
    • Voir le profil
Re : Problème de transparence sf::Image lorsque j'ai une image en background
« Réponse #11 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