C Elegance


chimpoid

Member
Joined
Jan 15, 2006
Messages
132
Age
50
Location
Scotland
Website
Visit site
Hi all,

I'm plowing on with my first game/c++ project and have noticed that since switching from using bitmaps with a colorkey to alpha keyed .png files there has been a small dent made in performance.

To cover the basic layout of the current rendering stuff. It's a bit like this....
split.jpg


Rendering out each surface one at a time and then an SDL_Flip.
The backdrop, 3 penguins, layer 1, 3 penguins, layer 2, 3 penguins, layer 4. Flip.
Sooooo, all the surfaces except the backdrop rely on alpha transparency.
All layers are rendered each frame :(

I had looked at running a switch statement to only render the current "live" penguin. Each penguin is numbered and there is an int declared "pengInPlay". Each penguin has its own surface "p" followed by its number. So penguin one is on a surface called "p1" , penguin 2 is on a surface "p2", and so on.
This lets me render the layers in the correct order drawlayer("Backdrop"), drawlayer("p1").... in order to slot the penguins between the layers.

The problem I was getting was trying to use the int pengInPlay to construct a call to the corret surface. I tried sprintf to convert the int to a string and then concat after "p" to give the surface name but that fell apart. (thinking in php) So I am left with the option of running multiple if statements like so.
Code:
if (pengInPlay ==1){
drawlayer("p1");
}
//repeat for all penguins.

The other thought I had was to make 1 surface for 1 penguin. Then use a switch statment in the rendering section. In pseudo code.
Code:
case (current penguin is between 1 & 3):
draw the penguin layer 2nd;
break;
case (current penguin is between 4 & 6):
draw the penguin layer 3rd;
break:
etc.etc.

Does anyone have any suggestions as to the best route to take. I think that the second would be the fastest but I am keen to hear how others would approach the problem of ordering the sequence of surfaces to be blitted.

I'll update the game on the site in a few minutes and pop the source code there as well.(don't laugh :D )
Updated game and source are here - Latest Version


Thanks

Chimpoid.
 
Strings are pretty much the slowest way of referring to objects - one way or another, you're passing around wide data structures which don't provide a good index for your object.

The canonical way to do this is to pass a pointer to the data about the penguin to draw, either by passing a pointer to a Penguin struct to a C-style function, or by using a Penguin class with methods to draw the penguin. Either way, the penguin data object can hold a pointer to the SDL surface or whatever you need when you're drawing that particular penguin. I don't know any SDL but I'd be surprised if it doesn't fit into this model.

You can then store pointers to your penguin data in an array, and index the array with the active penguin number for example - or even store the active penguin simply by pointer, whichever you prefer.

I don't know if you were already aware of this - sorry if I've missed some particular reason why you want to use strings in this way.
 
Yeah, I'm moving from PHP/Actionscript, Lingo etc into C so I am full of bad habits <_<
The penguin class has a function to draw each instance of penguin CPenguin::drawme() or something I called it.
The problem is that although drawing is handled nicely by the class I have to blit the each penguins surface to the screen in a preset order. The instance of Penguin's draw function is being called which blit's the current penguin image (in order to handle image sequences as animation) to it's own surface.
After all images have been blitted in order a final SDL_Flip is called to then blit all the surfaces to the screen.

I just worry that my attitude of "pick it up as I go along" is fine when it comes to making something that works but falls woefully short when making something that works well.

EDIT:Re-read the post.
So rather than fooling around with strings to get a reference to instances of the class I can just drop pointers in an array and then call
Code:
pengArray[(pengInPlay-1)].drawme();
where pengInPlay is the current penguin (1 -9)
And pengArray is ["*p1","*p2","*p3"......]

Must play with that a bit. It's nice to explore and learn but sometimes I need a gentle shove in the right direction. Thanks for pointing that out :D

Chimpoid
 
Hi all,

I'm plowing on with my first game/c++ project and have noticed that since switching from using bitmaps with a colorkey to alpha keyed .png files there has been a small dent made in performance.

To cover the basic layout of the current rendering stuff. It's a bit like this....
split.jpg


Rendering out each surface one at a time and then an SDL_Flip.
The backdrop, 3 penguins, layer 1, 3 penguins, layer 2, 3 penguins, layer 4. Flip.
Sooooo, all the surfaces except the backdrop rely on alpha transparency.
All layers are rendered each frame :(

Looking at that picture I can say you might split the three layers with alpha to 6 ones. Only the upper part of them needs the alpha so that way (upper with alpha, lower just opaque) youd could save some processor time. Of course I don't know the whole game you are making but for that scene it should work ok.
 
Last edited by a moderator:
Radek:
Aaah. So the total size of the image will impact on memory when blitted with alpha?
A 320*240 image with a 1px line of alpha at the top would take far more memory (processing time I mean) than 2 images.
One 2*240 with alpha and another 318*240 without alpha?

That might help streamline it a bit. I was worried that it was the total number of surfaces I was using that was causing the problem but I can see how the format of the images might cause a lot of slowing.

Chimpoid
 
Just a quick first note: you do not need to flip after drawing each layer.

Just draw your screen and finally use SDL_Flip() to display it on the screen all at once -- that might save you some CPU cycles as well.

So: SDL_Flip(), once per frame, after drawing.

Now I'm off to read your post in more detail... ;)

Edit: Here's one more thing you can try:

Based on pengInPlay, you can calculate the coordinates of the rectangle on screen that contains the moving penguin. Now if it's guaranteed that only that part of the screen will see movement, you can call SDL_SetClipRect() before blitting. That way, SDL will only draw in the rectangle you specify, and not waste time redrawing things that haven't changed, which should be much faster.
 
Yeah, I made that mistake when I first started, flipping each layer. caused huge flickering until it dawned on me that flip MUST be called only once all the layers have been blitted.

The source is available (see sig.) so feel free to have a root about and see how I am working it at the moment.

Chimpoid
 
Radek:
Aaah. So the total size of the image will impact on memory when blitted with alpha?
A 320*240 image with a 1px line of alpha at the top would take far more memory (processing time I mean) than 2 images.
One 2*240 with alpha and another 318*240 without alpha?

That might help streamline it a bit. I was worried that it was the total number of surfaces I was using that was causing the problem but I can see how the format of the images might cause a lot of slowing.

Chimpoid

He wasn't talking about the memory usage, but the speed of blitting. The notched part of the field (the wooden panel) is the only part that requires non-opaque rendering, so cut that bit out into its own image and render it using the slower alpha rendering. Then render the rest of the field with an opaque render (much faster).

Why the switch to images with alpha? If you stayed with masked images you could use the hardware blitter and get a huge speed up.
 
Last edited by a moderator:
The switch to png with alpha was in order to allow for a higher number of colours and prevent some of the dithering in the images. It seems in retrospect that this was hardly an issue and I may have taken a bad route when attempting to prevent something that is not that noticeable.
In part the dithering was being caused by the antialiased black lines soaking up a lot of the 256 colors available as they passed along the edge of all the non-black sections.
I think that by sharpening the images I can remove the dither that was occuring.

It never occured to me that alpha based png would be a significantly higher hit than the .bmp with color keying (also I liked the more slimline code that could be used when loading and preparing to blit) I will have to check and see if the same rules apply to the bmp's as the png's (smallest possible area of image to be keyed) and split up the layers apporopriately.

I will convert the images back to bmp and color key them and see if that speeds things back up again.

Thanks

Chimpoid
 
The switch to png with alpha was in order to allow for a higher number of colours and prevent some of the dithering in the images.
...
In part the dithering was being caused by the antialiased black lines soaking up a lot of the 256 colors available as they passed along the edge of all the non-black sections.

Er? Bitmaps and PNGs (can) have the same color depth, afaik, which is truecolor. You shouldn't need any dithering. And it's still possible to use colorkeying in truecolor mode, no problem, so there's no need to go to indexed colors.

It never occured to me that alpha based png would be a significantly higher hit than the .bmp with color keying (also I liked the more slimline code that could be used when loading and preparing to blit)

Well, as a future rule of thumb you can estimate that more complex operation == more expensive to perform. Compare "combining pixels" vs "ignoring pixels".

I will have to check and see if the same rules apply to the bmp's as the png's (smallest possible area of image to be keyed) and split up the layers apporopriately.

And the code really doesn't need to be all that different. The only difference is a call to SDL_SetColorKey() (instead of relying on SDL_image to load a surface with alpha channel built-in).
 
Last edited by a moderator:
Rixor,
BMP can be high colour as well but the filesize was scaring me. I did some checks and saw that PNG was 51kb, BMP was 227kb. After seeing that, I switched to indexed color bitmaps and got 77kb or 43kb using RLE.

I think I am making the mistake of worrying about loading too much into memory when the real issue is how much the processor has to work to display the image.

Compare "combining pixels" vs "ignoring pixels".
Exactly what I was thinking earlier after reading some of the posts here. As always, these things seem clear to me after I've had time to sit down and think about them.

Thanks your help everyone, I'll try and do a new version tonight and upload.

Chimpoid
 
Rixor,
BMP can be high colour as well but the filesize was scaring me. I did some checks and saw that PNG was 51kb, BMP was 227kb. After seeing that, I switched to indexed color bitmaps and got 77kb or 43kb using RLE.

I think I am making the mistake of worrying about loading too much into memory when the real issue is how much the processor has to work to display the image.

That is file size, not memory size. The image data is compressed, or not, in the file, but when you load them into memory, they use the same amount of space.

If you have a 64x64 true colour image in a BMP or PNG, it will have different file sizes, but in memory it will still use 64x64x3 (assuming no alpha) bytes of memory.
 
Last edited by a moderator:
That is file size, not memory size. The image data is compressed, or not, in the file, but when you load them into memory, they use the same amount of space.

If you have a 64x64 true colour image in a BMP or PNG, it will have different file sizes, but in memory it will still use 64x64x3 (assuming no alpha) bytes of memory.

Hah, I actually did laugh out loud. No amount of fancy compression stuff is going to make a stitch of difference once it's decoded and loaded into memory is it?
How the hell did I manage to miss that one? Once again it appears obvious in hindsight but it never once crossed my mind to think in terms of raw pixels stored in memory rather than compressed images stored on disc.

Thanks for that, I'll keep it in mind ( or memory) :D

Chimpoid
 
Last edited by a moderator:
Stupid me, I linked the updated version on the site to the old executable.

Finished converting everything back to bitmaps and added some scoring etc. Working well now once I tidy up the gameplay and set the speed up. Now I can get back onto doing the death animations and then some sound.

Latest Version

Chimpoid
 
also, if you absolutely need alpha, inopia clued me in to the fact that in photoshop you can make 32-bit ARGB bitmaps (one byte per channel, including alpha channel). this saves you from having to load pngs, if that makes any difference.

edit: typo
 
Damn :(
I left photoshop behind when I ditched windows a wee while back. I believe Crossover Office supports up to version 7 so I might have a nose at it.

I managed to fix a lot of the problems and the game is now at v1.0 ready to go. Source code is also on the site (see my sig). The bitmaps with colorkey work very well and it is a lot cleaner rendering. The only minor point is a little tidying up of the penguins where there is some bleeding around the edges. The gfx. were all done in inkscape and then exported as PNG, downsampled to indexed color and exported from Gimp.

Hopefully my next game will be a little cleaner and slighty more indepth. (Current request is for an Action Man themed game of matching pairs for my kid)

If anyone wants to rip apart the source and point out errors, kludges etc. I would be most appreciative.

Chimpoid
 
Back
Top