Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 2D Games with OpenGL



On Sep 18, 2004, at 10:12 AM, Alex Eddy wrote:

(I considered taking this off-list, but the discussion is still relevant to GL. It's a bit long though, so apologies to those of you who already have enough to read!)

Yes, I suppose I am dragging this out a bit, so I should also convey my apologies to other's on this list. I haven't looked into OpenGL for 2D games for years now (since OS 9 was the primary OS), so please forgive my ignorance.


Yes, slightly, assuming relatively modest object counts (say, a dozen layers, one thousand sprites.) You trade per-frame CPU sorting for the depth buffer clear time and the per-pixel depth test comparison. These are very optimized on recent GPUs though so it won't make a big difference. You will however also save the VRAM used by the depth component of the framebuffer, which might be nice if you're already low on VRAM.

Well every bit of VRAM counts :-)

If you are intending to update textures often, then you should stick to 32 or 16 bpp BGRA. If you really want to have 15 bit RGB and 8 bit A, then you'll have to make one RGB texture and one A texture and use a second texture unit to mask. Also, be warned that while this will save you 8 bits per texel on the ATI cards, I'm pretty sure that the nvidia cards don't support an A8 internal texture format-- they will upconvert it to L8A8 behind your back, so you'll still be using 32 bits in VRAM. It's probably easiest to just use RGBA8 if you need 8 bits of alpha. RGB5A1 is fine if you don't care about the alpha, and well worth the VRAM saving if you can stand some color quality loss. (The ATI cards also support R3G3B2, if you really want to pack the textures in, but it looks pretty bad and isn't supported on nvidia.) You might also check out the DXTC compressed formats, many games use these. They're only appropriate for prerendered artwork that isn't being animated though.

Well it wasn't something that I was dead set on. I've just used 15-bit images with 8-bit alphas (for the mask) in past, and then I would write a blitter to use the 8-bit alpha for transparency. I suppose I can upload a RGBA8 texture to the card and then some how have OpenGL to use the 8-bit alpha for transparency so I get the same result?


Yes, the render-to-texture texture is treated as a wrap-around work area (aka "toroidal scrolling region.") You draw into it wherever the newly exposed area is, and then blit then whole thing as four quads (or two, if you only need strict vertical or horizontal scrolling) to the viewport.

It's exactly as useful. You keep a render-to-texture work texture for each parallax layer, and in each of these you only update a small portion every frame. But you composite them all stacked on top of each other, updating the entire viewport, every frame. (Unless you have a really good reason, you should throw away any old CPU-era notions you have about tracking dirty rectangle updates in GL. Just update the whole viewport, let the GPU do its thing.)

That makes sense, I just wasn't thinking about using the render-to-texture texture for single image backgrounds (which is what my background layers), but as you've pointed out it's probably the best solution.
Well I've got no reason to deal with dirty rects any more - I didn't like them in the past anyways :-)


Note that overall, this method will end up using more total texture RAM than you'd need just drawing artwork layers directly into the viewport. But it minimizes AGP paging in the case where you have tons of artwork, by caching the currently visible layer portions into work textures in VRAM. And it allows you to treat each layer as a single texture, which eliminates filtering artifacts (that you would have, drawing a layer as i.e. a mesh of quads each textured from disparate portions of a texture altas) and enables various effects that might otherwise be costly (reusing the same layer multiple times, transforming a layer as a single object, etc.)

Also, I should probably clarify the difference between my using the term "render-to-texture texture", and John's talk about updating subtexture portions. In the simple case of 2D panning over huge artwork, all you need to do is glTexSubImage2D the appropriate areas (this is in fact what my simple TileScroller demo does.) But for more interesting games, you might want to creatively reuse artwork elements in your layers, so you really need a render-to-texture context per layer. Then you can draw from the artwork however you like; transforming, colorizing, etc the artwork pieces as you update the exposed portion of the layer. I'm sure you can come up with some interesting applications if you think about it.

Well at times I plan on manipulating the entire screen image such as rotations, and scaling it...
And many tiles will be animated so I'll be forced to redraw some of them almost every frame...
More on this below...


No, that actually won't work if you are using rectangle textures (which are, btw, required for optimal texture uploads) because REPEAT wrap mode isn't supported. If you simply want to fill the viewport with large repeating art just draw four (or two, for strict H/V scrolling) quads textured from the appropriate section of the artwork. However, if you want rotation, or your viewport scale does not match your texture scale (as may be the case when you need to support multiple display resolutions) or you otherwise need fractional texturing (for example scrolling by subpixel amounts) then you will have to watch out for filtering artifacts at the quad seams. In the render-to-texture approach I used in my Tilescroller demo, I handle this by faking REPEAT mode; I make the layer texture slightly bigger than it needs to be (2 texels wider, rounding up to the nearest 8 texels, and 2 texels taller) and copy any updated edge texels to the opposite border. But you can also check Apple's OpenGL Image sample code for how to handle it manually by overlapping the quad edges in the right way.

So there went my first ideal for multiple scrolling layers. I suppose that leaves me with one of two options, the render-to-texture option you have given me or simply creating a few extra quads and leap frogging them over one another (such as when the user scrolls right I would "leap frog" the left quad to the right of the other) - not a very pretty method so I leaning much more toward the render-to-texture option.


So my requirements are like so...redraw some tiles & sprites every frame, parallax scrolling, and per layer or entire screen effects - scaling, rotation, etc.
So I guess my current plan is to use the render-to-texture method for the background layers, then have a quad grid for the tiles, and then simply use different quads for the sprites.
So then I simply have 4 quads for each background layer which resize as needed. And then draw the quads for the tiles and sprites.
I suppose I could just apply the same matrix to each of the quads to allow for rotation and scaling etc.
Please correct me where I'm headed in the wrong direct - it's a lot better to know now than later when it's to late.


hope this helps (and you were able to read through my excessive use of parentheses)

It helps a lot, believe me for someone who hasn't looked into this in years its truly a wealth of knowledge.


- lee
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Mac-opengl mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/mac-opengl/email@hidden

This email sent to email@hidden
References: 
 >Re: 2D Games with OpenGL (From: Alex Eddy <email@hidden>)
 >Re: 2D Games with OpenGL (From: Lee Morgan <email@hidden>)
 >Re: 2D Games with OpenGL (From: Alex Eddy <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.