SFML community forums

Help => Graphics => Topic started by: RedTheGreen on October 14, 2012, 06:40:00 am

Title: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 14, 2012, 06:40:00 am
Does anyone know if there is an incompatibility here? My animation class runs smoothly every time, but when I try to automate the process of reading several animations by queuing them in an stl::list, they don't show on-screen.

I'm positive the issue is something like this. The function I'm calling to draw it returns the sf::Sprite of the current frame, but it isn't showing anything. The program doesn't crash or anything either, so I'm thinking the Image doesn't stay in memory when it's in a list.

Anybody know anything about this?
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: Laurent on October 14, 2012, 09:00:33 am
Can you show the code where you load the images, store them in the list and assign them to the sprites?

You have to be careful about copies that can happen; have a look at the last paragraph of the sprite tutorial.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 15, 2012, 05:50:45 am
Animation class
class Animation
{
    sf::Image img;
    std::list<AnimationFrame> frames;
    AnimationFrame currentFrame;
    void CheckFrames();

    public:
    void LoadFromFile( std::string filename );
    void SetPos( float x, float y );
    sf::Sprite Output();
};

Function to load image
void Animation::LoadFromFile( std::string filename )
{
    XMLDocument file;
    file.LoadFile( filename.c_str() );
    XMLElement* root = file.RootElement();
    img.LoadFromFile( root->Attribute( "image" ) );
    int w, h;
    w = root->IntAttribute( "w" );
    h = root->IntAttribute( "h" );
}
 

Function to store in list
void BuildMapFromFile( std::string filename )
{
    XMLDocument file;
    file.LoadFile( filename.c_str() );
    XMLElement* root = file.RootElement();

    //obj_animation
    for( XMLElement* animation = root->FirstChildElement( "animation" ); animation; animation = animation->NextSiblingElement( "animation" ) )
    {
        //object
        object new_object;
        new_object.type = "animation";
        int depth = animation->IntAttribute( "depth" );
        new_object.depth = depth;
       
        new_object._animation.LoadFromFile( animation->Attribute( "source" ) ); //loads image
        new_object._animation.SetPos( animation->IntAttribute( "x" ), animation->IntAttribute( "y" ) );

        std::list<object>::iterator i = q_object.begin();
        bool varadded = false;
        while( i != q_object.end() )
        {
            if( i->depth > depth )
            {
                q_object.insert( i, new_object );
                varadded = true;
                i = q_object.end();
            }
            else ++i;
        }
        if( varadded == false ) q_object.push_back( new_object );
    }
}

The animation class loads its own image, which is kept inside the class (not the best idea, I know). The class itself is moved into the list.

EDIT: I just tried setting the sprites to a globally-declared image, and it failed as well.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: Laurent on October 15, 2012, 08:02:31 am
Quote
The class itself is moved into the list.
So this is exactly what is described in the tutorial. Don't forget that the list stores a copy of your object, and that a copied sprite will still use the same image as its source, not the copy of the image which is often made at the same time. It's hard to verify here because you don't show all the relevant parts of your code.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 16, 2012, 02:47:39 am
That's something I wasn't really thinking about. I'll keep it in mind from now on.

That's now fixed, but it's still failing. Even if I use a globally-declared image, it fails.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: Laurent on October 16, 2012, 08:06:34 am
Then show a complete and minimal code that reproduces this new problem.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 17, 2012, 05:18:06 am
Here's a modified copy of my code in a Code::Blocks project. It requires SFML 1.6.

https://sites.google.com/a/redthegreen.com/files/Flow-Dev.zip?attredirects=0&d=1 (https://sites.google.com/a/redthegreen.com/files/Flow-Dev.zip?attredirects=0&d=1)

There's also a new issue of crashing that only occurs when compiling under Release. If you compile under Debug, it won't crash. Keep that in mind when testing.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: Laurent on October 17, 2012, 07:46:44 am
Please read this carefully:
http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 18, 2012, 06:49:46 am
Woops. I guess I should have read that first.

Anyway, here's a simple example I whipped up quickly. This should be a bit easier to read.

#include <SFML/Graphics.hpp>
#include <string>
#include <list>

struct ComplexImage
{
    sf::Image img;
    std::string file;
};

std::list<ComplexImage> buffer_image;

sf::Image GetImage( std::string filename )
{
    std::list<ComplexImage>::iterator i = buffer_image.begin();
    bool varfound = false;
    while( i != buffer_image.end() )
    {
        if( i->file == filename )
        {
            varfound = true;
            return i->img;
        }
        else ++i;
    }
    if( varfound == false )
    {
        //create new image
        ComplexImage new_image;
        new_image.img.LoadFromFile( filename.c_str() );
        new_image.file = filename;

        buffer_image.push_back( new_image );
        return GetImage( filename );
    }
}

int main( int argc, char* argv[] )
{
    sf::RenderWindow game( sf::VideoMode( 800, 600, 32 ), "App Title" );
    sf::Event event;

    sf::Sprite test_sprite;
    test_sprite.SetImage( GetImage( "ball.png" ) );
    test_sprite.SetPosition( 40, 40 );

    while( game.IsOpened() )
    {
        while( game.GetEvent( event ) )
        {
            //if window is closed or Escape key is pressed, close the game
            if( event.Type == sf::Event::Closed or ( event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Key::Escape ) ) game.Close();
        }

        //clear display
        game.Clear( sf::Color( 100, 149, 237 ) );

        //draw sprite
        game.Draw( test_sprite );

        //update display
        game.Display();
    }

    return EXIT_SUCCESS;
}
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: Laurent on October 18, 2012, 08:13:09 am
Thanks :)

With this code I spotted the problem in no more than 2 seconds.

GetImage returns a temporary copy of the original image, which is destroyed immediately after being given to the sprite. You must return a reference (sf::Image&).
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on October 20, 2012, 04:46:44 am
Alright! Thank you! I was planning on doing that anyway, but I didn't realize I had to.
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: kaB00M on October 25, 2012, 04:28:27 am
Why not use std::map?

std::map<string, ComplexImage> buffer_images;

if (buffer_images.find(name) != buffer_images.end())
{
    return buffer_images[name];
}

//add into map
buffer_images[name] = ComplexImage; //etc
//etc
 
Title: Re: Incompatibility with sf::Image and stl::list??
Post by: RedTheGreen on December 04, 2012, 04:43:21 am
Maybe I should. Good idea.