SFML community forums

Help => Graphics => Topic started by: dpixel on September 09, 2013, 04:12:36 pm

Title: Image too large?
Post by: dpixel on September 09, 2013, 04:12:36 pm
Hi all,

I was getting a "white sprite" problem.  It shows up fine on one computer and as a white box on another. 
And I thought it was the sf::Sprite, sf::Texture scope, after reading around.    I narrowed it down that the image was too big for the vid card.  The width was 2089 and I cut it back to 2048 and everything was fine.

Anyway, I have a lot of graphics in this game and there will be more.  I've read in the tutorials that it's best to have as few textures as possible, but I did not understand why from the reasoning.  Could someone explain in more simple terms.   Thanks.
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 04:29:54 pm
I've read in the tutorials that it's best to have as few textures as possible, but I did not understand why from the reasoning.
Is it really written in such a general way? There is no fundamental problem with multiple textures. It takes some time to switch between different textures (far more than to switch texture rectangles), but unless you draw loads of elements, this won't be an issue. On the other hand, by creating overly large textures, you lose compatibility to older graphics cards.

In case you need bigger continuous textures, for example to display a background image, you could have a look at thor::BigTexture (http://www.bromeon.ch/libraries/thor/v2.0/doc/classthor_1_1_big_texture.html). It automatically splits the texture into smaller textures that can be stored by the graphics card, providing a transparent API to the user.
Title: Re: Image too large?
Post by: dpixel on September 09, 2013, 04:51:49 pm
I guess I'm confused about "switching between different textures".   I don't know if I'm doing that...lol

Every .png file I have is loaded into a texture and then assigned to a sf::Sprite.  Then I just blit parts of the sprite I need.
I just want things running effeciently as possible.
This is what I'm doing:
    sf::Texture interfacetexture;
    sf::Sprite interface;

void init()
{
    interfacetexture.loadFromFile("interface.png");
    interface.setTexture(interfacetexture);
}

void Blit(int x, int y, int srcX, int srcY, int srcW, int srcH, sf::Sprite sprt)
{
    sprt.setPosition(x, y);
    sprt.setTextureRect(sf::IntRect(srcX, srcY, srcW, srcH));
    window.draw(sprt);
}

 
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 05:38:46 pm
Texture switches occur every time a sprite (or another drawable) is rendered with a different texture than the one before. I'm not entirely sure how smart SFML and OpenGL are when the same texture is bound multiple times in a row, but I strongly assume it will be faster than binding different textures.

Anyway, your blit mechanism is quite questionable. Have you used SDL before? The typical use case in SFML is: You have a sprite and set a texture, which doesn't change after initialization. Depending on the game logics, you set the transforms (position, rotation, scale), possibly color and texture rect (for animations). Don't try to mimic blitting or immediate rendering as you know it from ancient graphic APIs. Also, don't copy sf::Sprite if it's not necessary; pass it by const reference.
Title: Re: Image too large?
Post by: dpixel on September 09, 2013, 07:00:48 pm
I'm always using the same texture with the same sprite.  Just the x, y source is changing to get the right frame.

And yes.  I ported my game from SDL to SFML.  Except for the audio, which crashes on exit.  (Already have a post on here about that)

This Blit function works surprisingly well, which is mostly used on animations...which is why my .png files are large...I try to keep all the frames on the same X position, so the png width gets long.

Is there some sort of performance problem with the way I'm doing this?  My goal was to put something on the screen with one line of code.
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 07:15:11 pm
I'm always using the same texture with the same sprite.  Just the x, y source is changing to get the right frame.
No, you're not. As already mentioned, you're copying the sprite every time you draw. Thus, you have a different sprite for every Blit() call.

But why don't you store different sprites in the first place, instead of recycling sprites and adjusting their texture rects again and again? I hope it's not for performance reasons...

And yes.  I ported my game from SDL to SFML. [...] This Blit function works surprisingly well
Of course it works, but you should not try to apply SDL 1.2 concepts (which are antiquated, to say the least) directly to SFML. This tutorial (http://www.sfml-dev.org/tutorials/2.0/graphics-draw.php) explains how to render objects with SFML, using the object-oriented approach of sprites instead of immediate drawing.

My goal was to put something on the screen with one line of code.
But with this approach, every caller of Blit() has to know the texture rect. If you draw the same sprite multiple times, you have to pass the coordinates multiple times. You have magic numbers across your whole application. If a texture rect changes, you have to adapt many different places.
Title: Re: Image too large?
Post by: dpixel on September 09, 2013, 07:36:32 pm
Quote
But why don't you store different sprites in the first place, instead of recycling sprites and adjusting their texture rects again and again? I hope it's not for performance reasons...
That would be a lot of sprites.  I didn't think it would be done that way. 
How big of a performance hit am I taking adjusting the texture rect every time?

Quote
using the object-oriented approach 
Yeah, I'm a bit old school with bad habits.  I'm using no Classes, only structs...lol

Quote
You have magic numbers across your whole application.
Yes I do.  LOL

I'll try and wrap my head around that tutorial
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 08:24:16 pm
To be clear: Performance is not the crucial factor for one or the other way. It will really take a lot until you reach the limits, and once you do so, the bottleneck will be somewhere else.

Much more important is clean code, as it will shrink the development, maintenance and debugging time dramatically. If you're used to old habits, you should probably read a current C++ book, maybe even one that deals with C++11. It's of great advantage to know the programming language well, as it will save you a lot of time and pain.

So please don't favor ancient techniques because you think they are faster (such assumptions are usually wrong), instead focus on writing code that will be easy to maintain and extend. Typically, optimizations are then also simpler to achieve.
Title: Re: Image too large?
Post by: Hanmac on September 09, 2013, 08:43:19 pm
hm about Texture and BigTexture, exist a way to check if an Texture is to big to be an normal Texture from inside the program?
and wouldn't be some kind of TextureInterface/SpriteInterface class would be more nice for the programmers?
Title: Re: Image too large?
Post by: Ixrec on September 09, 2013, 08:53:15 pm
I believe the static function Texture::getMaximumSize() answers your first question.

Edit: The API documentation also gives this hint:
Quote
This maximum size is defined by the graphics driver. You can expect a value of 512 pixels for low-end graphics card, and up to 8192 pixels or more for newer hardware.
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 09:18:51 pm
and wouldn't be some kind of TextureInterface/SpriteInterface class would be more nice for the programmers?
What would it look like? Or how would it differ from thor::BigTexture and thor::BigSprite (see link in my first answer)?
Title: Re: Image too large?
Post by: Hanmac on September 09, 2013, 09:23:59 pm
and wouldn't be some kind of TextureInterface/SpriteInterface class would be more nice for the programmers?
What would it look like? Or how would it differ from thor::BigTexture and thor::BigSprite (see link in my first answer)?

if you compare them you will see that they are a bit different but not the same (some functions from Texture are missing in BigTexture, and some setter does not have corresponding getter methods), and i wanted to use something that automatically uses BigTexture if the Texture you want to use is to big ...
Title: Re: Image too large?
Post by: dpixel on September 09, 2013, 09:56:41 pm
To be clear: Performance is not the crucial factor for one or the other way. It will really take a lot until you reach the limits, and once you do so, the bottleneck will be somewhere else.

Much more important is clean code, as it will shrink the development, maintenance and debugging time dramatically. If you're used to old habits, you should probably read a current C++ book, maybe even one that deals with C++11. It's of great advantage to know the programming language well, as it will save you a lot of time and pain.

So please don't favor ancient techniques because you think they are faster (such assumptions are usually wrong), instead focus on writing code that will be easy to maintain and extend. Typically, optimizations are then also simpler to achieve.

To be honest, I've just started learning c++ about 6 months ago.  I've always wanted to, but thought the learning curve was too steep for me.  My programming experience goes back 20+ years though, with languages such as vb, pascal, etc.  And then to my surprise, c++ wasn't that hard after all.  And paired with a graphics library, I was able to do pretty much anything I wanted.  Plus the internet is a world of information I never had years ago.
I know my code isn't  modern by todays standards, but I still have fun making my little games.
And because oop is a new concept to me and I'm not one to ask a lot of questions, I tough it out in other ways.   Old dog new tricks syndrome.   
I do need to understand more concepts of oop, but I'd be asking 50 stupid questions on here before I finally get it...lol
Title: Re: Image too large?
Post by: Nexus on September 09, 2013, 10:14:13 pm
if you compare them you will see that they are a bit different but not the same (some functions from Texture are missing in BigTexture, and some setter does not have corresponding getter methods), and i wanted to use something that automatically uses BigTexture if the Texture you want to use is to big ...
I'm not sure if it's possible to have exactly the same API for normal and big textures, because of technical limitations.

E.g. setRepeated() is simple for sf::Texture: You pass the flag GL_REPEAT at texture creation, and OpenGL handles everything. thor::BigTexture would require to modulo the texture rect every time a thor::BigSprite is rendered, and choose the (up to infinite) correct sprites to display the desired rectangle. It would not only lead to a mess of an implementation, but be quite inefficient...

I do need to understand more concepts of oop, but I'd be asking 50 stupid questions on here before I finally get it...lol
Then be prepared to hear "Learn C++ first" again and again :P

On a serious note, there are tons of people like you: They know other languages, learn the bare bones of C++ and think that's enough. It is not, C++ is one of the most complex programming languages; it has many specific language features, rules and exceptions, and even more pitfalls. It is crucial to not only learn the basics, but also the paradigms, idioms and best practices. Of course it's possible to write simple games with easy-to-use libraries like SFML and without greater knowledge, but as soon as you want to develop something bigger with greater requirements regarding robustness, efficiency, maintenance, you'll be very glad about deeper C++ knowledge. The mistake people make is thinking they can save time by skipping advanced topics; eventually it will cost them triple the time to develop, maintain and debug ancient code -- additionally, it's a very frustrating experience.

I don't want to discourage you, but you should be aware of the complexity and not underestimate C++. If you just want to develop some simple games, one option would also be a simpler language. SFML has bindings for many programming languages.
Title: Re: Image too large?
Post by: dpixel on September 09, 2013, 10:57:29 pm
I'm aware of the complexities of c++.  This is why I held off learning it for so long.
What I liked right of the bat was how it kind of forces me to write cleaner code.  I wasn't expecting that.  If that makes any sense.
But, I do find myself chasing my tail when adding features to my programs, which I believe is some of what you were getting at.

Stupid Q #1:
Back to the sprite thing.  Is it normal to have 100's of sprites in a graphically intensive game? (All with their x, y, h, w sources set of course)
I'm writing a platformer zombie shooter/adventure thing.  I have 3 different zombie explosions of 14 frames each.  Would that be 42 sprites?  Plus all the other 100+ frames of other stuff.
Title: Re: Image too large?
Post by: Ixrec on September 09, 2013, 11:03:20 pm
Yes it's normal to have hundreds of sprites.  The sprite class itself is very lightweight, since it essentially just stores some information like position and rotation to be used when drawing the underlying texture.  The texture is the expensive part.

For a fixed animation like a 14 frame explosion, I believe the right way to do it is put all 14 frames in one texture, and change the sprite's textureRect every frame (using setTextureRect()).  I don't think there's much point in multiple sprites, not for performance reasons, but because it's more intuitive and logical to have one sprite changing each frame than 14 sprites you cycle through.

Of course it may be even better to put all your zombie related images in a single big texture and have for example one row with frames for the walking animation, one row for the idle animation, one row for each of your explosion animations, and so on.  In the long run you'd probably abstract all this into a Zombie class with methods like startExploding(), so that only the Zombie class itself has to worry about exactly what textureRect to use every frame.
Title: Re: Image too large?
Post by: dpixel on September 10, 2013, 02:22:22 am
Yes it's normal to have hundreds of sprites.  The sprite class itself is very lightweight, since it essentially just stores some information like position and rotation to be used when drawing the underlying texture.  The texture is the expensive part.

For a fixed animation like a 14 frame explosion, I believe the right way to do it is put all 14 frames in one texture, and change the sprite's textureRect every frame (using setTextureRect()).  I don't think there's much point in multiple sprites, not for performance reasons, but because it's more intuitive and logical to have one sprite changing each frame than 14 sprites you cycle through.

Of course it may be even better to put all your zombie related images in a single big texture and have for example one row with frames for the walking animation, one row for the idle animation, one row for each of your explosion animations, and so on.  In the long run you'd probably abstract all this into a Zombie class with methods like startExploding(), so that only the Zombie class itself has to worry about exactly what textureRect to use every frame.

Thank you for this explanation.   This clears some things up for me.

I should really start experimenting with classes.  I understand how they are assembled, but it's the real world application part I don't quite get yet.   Right now I use this:
struct undead{
    bool alive;
    int state;
    int x;
    int y;
    int direction;
    int animation;
    int zombienumber;
    int instruction_set;
    int counter;
    int old_count;
    int explosion;
} zombie[400];
 

Which could be part of a class public part.
And when did they start calling functions, methods?   I thought that was a java thing.   :P
Title: Re: Image too large?
Post by: Ixrec on September 10, 2013, 02:31:58 am
A method is simply a function that's in a class.  The term applies to OOP in any language.  Since Java requires that everything be a class all functions are automatically methods (to oversimplify it).

What methods you put in a zombie class depends entirely on how you want your game to work, but aside from the constructors (you'll read about those) some obvious possible candidates are draw(), setPosition(), setPatrolRoute(), takeDamage(), attackPlayer(), and maybe takeDamage() will call a private function like explode() if it discovers the zombie lost its last HP, etc etc.  And later on you might find yourself duplicating these functions in several enemy classes so instead you might make a base class called Enemy and have each class inherit from that.  We could go on and on.

By the way, Java's OOP really isn't that different from C++'s OOP, so you'll see a lot of other terminology that carries over.  The biggest differences I know of offhand is that Java adds Interfaces (in C++ terms these are like abstract classes with no concrete parts) because that provides a simple solution for multiple inheritance in the rare cases you need it, and C++ has a bunch of extra features Java doesn't like operator overloading and templated everything and god knows what else (and C++11 added even more!).  That probably sounds like gibberish now, but it'll make sense eventually.
Title: Re: Image too large?
Post by: Nexus on September 10, 2013, 10:52:12 am
Also, instead of arrays with an arbitrary size (in your case 400), you can take STL containers such as std::vector, which are able to grow dynamically.
std::vector<undead> zombies;
zombies.push_back( undead(...) ); // insert new zombie

The STL is probably the most important and most often used part of the C++ standard library, you should definitely have a look at it :)
Title: Re: Image too large?
Post by: dpixel on September 10, 2013, 03:28:22 pm
Thanks.  I briefly touched on vector containers before for that very reason.  I will look into it more though.

The project I'm working on was actually supposed to be a learning tool, but it's turned into something I kind of like.  I'm a pixel artist as well and spend about half my time pixeling for this when I should be learning classes, etc.  I'm kind of a scatter brain, but I've accepted that.   :)
Title: Re: Image too large?
Post by: dpixel on September 10, 2013, 07:02:30 pm
After all this talk about oop and classes.  I created one.  As well as shooting, my player can throw bombs.
I used to have:

struct bomb1{
    int x;
    int y;
    bool available;
} bomb[99];
 

And now I have:

class BombClass{
    public:
        void setX(int X){
            x = X;
        }
        void setY(int Y){
            y = Y;
        }
        int getX(){
            return x;
        }
        int getY(){
            return y;
        }
        void setAvailable(bool a){
            available = a;
        }
        bool getAvailable(){
            return available;
        }

    private:
        int x;
        int y;
        bool available;
};
BombClass bomb[99];
 

And it all works.   :D
It seems like a lot of lines of code for what it does, but I had to start small and start somewhere.
Thanks for all the motivation and inspiration.
Title: Re: Image too large?
Post by: Ixrec on September 10, 2013, 07:58:20 pm
Yeah, trivial getters and setters tend to eat up a lot of space.  In theory you should only need to add those methods when getting or setting has some additional step (eg, checking the value is valid), and you can't simply make the members public or let the constructor handle it.  But in the real world it's best to add them early on so that all the code using this class won't need to be rewritten when you inevitably change how the class works internally.

With that said, it may be better to combine x and y into a single sf::Vector2i or std::pair<int,int>.
Title: Re: Image too large?
Post by: dpixel on September 10, 2013, 09:42:52 pm
Yeah, trivial getters and setters tend to eat up a lot of space.  In theory you should only need to add those methods when getting or setting has some additional step (eg, checking the value is valid), and you can't simply make the members public or let the constructor handle it.  But in the real world it's best to add them early on so that all the code using this class won't need to be rewritten when you inevitably change how the class works internally.

With that said, it may be better to combine x and y into a single sf::Vector2i or std::pair<int,int>.

This was just kind of a retrofit for the rest of the program.  Just to see how it would work.  I can start to see some possibilities tho.

Stupid Q #2:
Is it common for class methods to use other class methods or even plain old functions throughout the program.  Or are they generally self contained?
Title: Re: Image too large?
Post by: Ixrec on September 10, 2013, 11:09:17 pm
It's very common, and there's nothing wrong with it.

However, the class as a whole should be "self-contained" to some extent.  The idea behind putting functions into a class is so that you can exhaustively define all the operations the rest of program is allowed to perform on it, which makes it easy to debug/design the class separately from the code that uses it.