'Miner49er' said:
I think paeryn's explanation seems to make the most sense.
Trust Paeryn... Trust Paeryn...
Seriously, he's the author of one of the accelerated ports of SDL to the GP2X, so he probably knows what he's talking about.
You will really want to watch the Surface formats, though, because as has been pointed out, blitting between surfaces of different formats hits performance hard. You'll probably want to just make sure that you convert all surfaces to the same (screen) format before you do anything else.
I don't think there is any "right" answer, though.
With one large "contact sheet" of sprites you:
- Might have a larger image than necessary (i.e. your images might have to be made to a fixed size, which means some would waste space etc.)
- Have one large contiguous block of memory instead of many disparate blocks (and you would know instantly if you had enough RAM to run the game, rather than finding out when you try to load the 1000th sprite).
- Would use a small array of probably only byte-sized offsets to describe each potential sprite.
- Have one bitmap decode once into memory for the whole program.
- Have a lot of stuff in RAM that may *never* get used.
With many small sprites you:
- Can load and unload them dynamically (i.e. only load those particular sprite necessary at that moment).
- Can easily change a single sprite without having to re-ship the whole bitmap.
- May incur a lot of alignment / surface / pointer / malloc / free overhead if you have a LOT of images.
- Will have to do lots of small decodes on small image files.
- Will waste some disk space in filesystem allocation (unless you store the sprites as a contact sheet but split them into individual surfaces once they are in RAM).
I would personally use small, independent bitmaps to start with until you have a way for array access to those bitmaps and some nice structured bitmaps on disk to play with and, most importantly, a game to play. That's purely for simplicity and because until you actually run into performance issues, the easiest way is usually more than good enough.
If I started going further with that particular program, then I'd probably have larger per-sprite sheets with their complete animations for a single sprite and load them as and when necessary (e.g. the sheet for the boss character or whatever will only be in RAM when he's around, but I would load *every* animation frame to do with him in one hit as soon as he appeared by loading one large bitmap of him and blitting individual frames from it).
If in doubt, test, and test on the actual hardware you are targetting. I always find the best function to include in any program I write is one that prints a message preceded by the exact time... then I can just add a line (usually inside pre-processor macros) in my code to time how long individual functions/lines of code last. (Yes, you can do this with fancy profilers and debuggers, but I find manual printf's are easier to customise.) Then you just try a small experiment with two spriteloaders and see if they differ... if they differ by a significant amount, try to find out why (it might well be something stupid like surface formats, etc.) and if you can't find out why then use the one that gives best performance. Such things are usually so dependent on your particular needs (i.e. does it need to multitask with another thread, does it need to load a large boss character *instantly*, does it do heavy animation, are your bitmaps large enough to kill caches etc.) that the only way is to try for yourself and see.
When starting in coding, write *everything* in a function/procedure/whatever you want to call it with a fixed interface... then when LoadSprite and BlitSpriteToScreen are slow, you just write replacment functions that tries a different way (e.g. full contact sheet instead of individual bitmaps, even if that means that LoadSprite becomes effectively a null function). If it doesn't work faster, you can keep the code for the corner cases that don't need to be fast, or as a double-check that your fast function works the same. If it does work faster, a simple search and replace means the whole program benefits instantly.
I did this with one of my programs... I needed a "Draw Polygon Outline To Screen" function, and I had SDL_gfx's version, but I was having debugging problems - my polygons weren't always closing properly. So I quickly knocked up function that took the same interface and made one which used SDL_gfx's "Draw Line" in a loop to draw the entire polygon. It helps you test performance, see whether you can reduce code use, and spot problems in your functions (in this case, the function was over-running the data given because of a stupid off-by-one and drawing the last lines of the polygon to a random location).
I've even deliberately gone back and rewrote entire game-solver routines (which are NOT easy to write) in a mathematically different way in order to check that my code wasn't doing anything too stupid on corner cases that I didn't want to verify manually. Once, I got stuck on a particular function I needed, so I whipped up a stupid, slow version that worked, built the rest of the program I needed to use it (which was the bit that takes WEEKS, and would have just been held back if I'd spent a long time on trying to perfect the small function it used), and after I was getting the results I wanted, but just too slow, I got other people to write a replacement function that worked the same (I think paeryn even submitted an entry for that!). Because of the modular approach, it was simply a matter of copy/paste to test ten people's submissions to see if they worked better, and a small edit to put two functions side-by-side and check they always got the same answers.
Think modular... don't necessarily tie your program into one way of working and when you *do* decide to write the other method out of interest, you instantly get verification of results, performance comparisons, and plug-in replacement of critical functions. Then, if you move from SDL onto something else, you can just replace the functions to do similar things for Allegro, DirectX or whatever and not have to completely re-write the program.