2D Game Background (non-repeating)

Started by
15 comments, last by _the_phantom_ 18 years, 9 months ago
Hey there, For my 4E4 entry I'm needing a large non-repeating background for my game. I'm wondering the best way to do this and maintain a decent speed. At present, I've loaded the whole background as a texture and rendered a textured quad behind the other spites (also other textured quads). Obviously, this is far from ideal so I'd like to call on your expertise in helping me solve this. Using the textured quad limits me to ^2 background sizes, something I'm not too keen on having. My game is low resolution (640,480) and so a 'small' background would be 1280x480 - creating a ^2 version of this texture would be a nightmare... One idea I had was to 'panel' the background. Take the source image and split it into smaller panels which are then rendered according to the appropriate view. A panel here would probably be tall and thin (640 or the next ^2 up x 256), but again it seems like it would be slow. An idea I had last night would be to use glDrawPixels to draw the bitmap striaght into the framebuffer. I assume I could specify which part to draw from, but I don't know how fast this will be... My graphics card is low-end (GF2 MX) with a fairly decent CPU (AMD 2800+), so the solution needs to be able to work on this setup. Anyone that's able to help will receive a nice rating bonus plus a credit in my 4E4 game entry as thanks. Thanks for your time!
Advertisement
First of all, textures need not be powers of two if you use one of the rectangular texture extensions: GL_ARB_texture_rectangle, GL_EXT_texture_rectangle or GL_NV_texture_rectangle. However, if 1280x480 is 'small', then you'll probably run out of texture memory pretty fast anyway. On top of that, the maximum width of a texture is only 4096 on my geforce3, and it certainly won't be better on your geforce2. This means tiling is probably your only option if you go for the texture solution.

glDrawPixels will probably be (somewhat) faster then the texture option from a rendering point of view. However, for your application, the function-call has a rather ackward specification:

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

Which means that each frame you will have to construct a new pixel-set of size width x height from your full buffer, which definately won't be cheap.

I would go for a tiled texture implementation as I believe the copy for glDrawPixels will kill any performance gains it has over using textures. The only way to know for sure is to try both, but I would go for the tiled texture solution first.

Tom
Quote:Original post by evolutional
Hey there,

One idea I had was to 'panel' the background. Take the source image and split it into smaller panels which are then rendered according to the appropriate view. A panel here would probably be tall and thin (640 or the next ^2 up x 256), but again it seems like it would be slow.

Thanks for your time!


If this is what you plan you should look into glAddSwapHintRectWIN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/glfunc01_16zy.asp).
This will allow you to rectangular areas to be copied on calling SwapBuffers. However this is for windows only. The advantage of this method is - this should speed up things significantly even if you run in software mode. With glDrawPixels I don't think that will happen.

Hope this helps.
The more applications I write, more I find out how less I know
Quote:Original post by dimebolt
First of all, textures need not be powers of two if you use one of the rectangular texture extensions: GL_ARB_texture_rectangle, GL_EXT_texture_rectangle or GL_NV_texture_rectangle.


I'm hoping that my crappy card supports that extension ;)

Quote:
glDrawPixels will probably be (somewhat) faster then the texture option from a rendering point of view. However, for your application, the function-call has a rather ackward specification:

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

Which means that each frame you will have to construct a new pixel-set of size width x height from your full buffer, which definately won't be cheap.


Could I not just store the image data in memory and alter the pointer to hte pixels instead of copying from one buffer to another? My data is kept in a form that's ready to be used by the OpenGL texturing functions, I'm hoping that I can set up glDrawPixels to read that buffer without a need for transformation. I'll check it out later.
Quote:
I would go for a tiled texture implementation as I believe the copy for glDrawPixels will kill any performance gains it has over using textures. The only way to know for sure is to try both, but I would go for the tiled texture solution first.


From what you've said I think I will give the tiled option a go first. I use a handle-based texture management system in my game, so I *should* be able to wire it up to cache the tile before it's displayed and uncache it when it goes of screen. This would be a good way of managing the backgound, essentially allowing me to have huge backgrounds without needing to keep the whole image in memory.

I'll give this a try tonight - thanks for your help :)

CRACK123: Thanks, I'll check out that function. I *did* want the game to be cross-platform though, but it could be a useful fallback if the method I'm planning doesn't work out too well.
Quote:Original post by evolutional
Could I not just store the image data in memory and alter the pointer to hte pixels instead of copying from one buffer to another? My data is kept in a form that's ready to be used by the OpenGL texturing functions, I'm hoping that I can set up glDrawPixels to read that buffer without a need for transformation. I'll check it out later.


Good point. You could call glDrawPixels(1, height, ...) width times (or the other way around, depending on the way your buffer is organized) with the proper pointers into your main buffer and using glRasterPos(...). Didn't think of that in the absence of my morning coffee. But still, I doubt it will be much faster than the texture solution. It might be interesting to try both though.

Tom

[Edited by - dimebolt on June 29, 2005 6:05:12 AM]
Quote:
Could I not just store the image data in memory and alter the pointer to hte pixels instead of copying from one buffer to another? My data is kept in a form that's ready to be used by the OpenGL texturing functions, I'm hoping that I can set up glDrawPixels to read that buffer without a need for transformation. I'll check it out later.


How about using compressed textures and using glTexCopySubImage* or glTexCopyImage* to modify parts of the background ? This could be a much more fasible solution than glDrawPixels. Plus this way you will only be changing the pixel information but using the same textures.

Hope this helps.



The more applications I write, more I find out how less I know
Quote:Original post by evolutional
Quote:
glDrawPixels will probably be (somewhat) faster then the texture option from a rendering point of view. However, for your application, the function-call has a rather ackward specification:

void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);

Which means that each frame you will have to construct a new pixel-set of size width x height from your full buffer, which definately won't be cheap.


Could I not just store the image data in memory and alter the pointer to hte pixels instead of copying from one buffer to another? My data is kept in a form that's ready to be used by the OpenGL texturing functions, I'm hoping that I can set up glDrawPixels to read that buffer without a need for transformation. I'll check it out later.

Afaik (I'll put a disclaimer here to be in the clear; it's been years since I last did anything OGL. My memory could very well be fuzzed on the topic) the major performance penalty that comes with using glDrawPixels is due to that you have to transfer such a large amount of data over the bus every frame. Also, iirc, there's additional penalties involved due to that the rendering pipeline on the card needs to be flushed and clear before such a transfer can be possible.

In conclusion, I would too vote for the tiled approach.

Again, all this is afaik and iirc.
-LuctusIn the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move - Douglas Adams
hmmm when i read this the approch which first sprung to mind would be to use textures, however you could be cunning about it [grin]

Load in your data into ram and create a texture which is the next power of two size above the screen size (so, 1024x512 if your screen size is fixed at 640x480). Then, use glSubTexImage() to update only a portion of it, you'll probably want to bench mark to see which size is optimal for updating, however my first thought would be screenwidth + a bit, so you can cheat slightly by scrolling the texture a bit before updates.

So, when you need to update the texture, us the glPixelStore functions to offset into the correct place in your source data and glsubtex the new infomation to the texture (this is where buffering a few extra pixels would be sane, to keep the memory nicely aligned when you update instead of incrementing by a pixel every time).

I'm not sure how fast this would be, so a bench mark might be a good idea, however glsubteximage should be pretty fast on anything post-gf2 so it seems like a viable solution to me.
I've just tried the idea suggested by _the_phantom_ and it seems it's too slow. The issue seems to be the giant texture being drawn.

I'm trying a glDrawPixel solution now, but it's still very slow. I'm wondering how else I can speed this up, I'm starting to doubt whether tiling will make any difference either :(
yeah, drawing speed is going to be a killer as you are basically filling the whole screen with pixels, glDrawPixels() certainly isnt going to be faster than the texture method because as well as filling the screen you are having to transfer the data across the bus.

Make sure you dont have any none required states set, for example when drawing the background you are going to want blending disabled as its a waste of time (with blending its a horrible read-modify-write cycle, without you just write) and make sure you are only writing the buffers required to try and cut down on the fill rate you are eatting up.

There is a chance that breaking the background up into tiles might well help, as it might allow better resource balancing, however I've never tried it so I'm not sure [smile]

How slow is too slow btw?

This topic is closed to new replies.

Advertisement