Scrolling Background

BlitzMax Forums/BlitzMax Programming/Scrolling Background

Hey Tony,

I don't know about DirectX but I can describe from an OpenGL viewpoint.

Originally, OpenGL started off by supporting textures that are 64x64. That was considered to be the standard minimum allowable size for a given texture. I guess they based that on thinking that it would be supported on as much graphics hardware as possible accross the board. So what this means is that even if you wanted an image that is really small, smaller than 64x64, it has to be stored `within` a 64x64 texture - and generally the rest of the pixels will be wasted.

As graphics hardware advanced it tended to support bigger texture sizes, although usually they would still be powers of 2 and always square. It's related to how the hardware was set up and how it optimized based on knowing the texture size etc. Probably. So nowadays on new cards you can have much bigger textures, and maybe your card even supports 2048x2048 textures without any problems, but the same is not true of all cards. So while something might work with that size texture, for you, it might fail especially on older gfx cards for other people. Generally speaking people say that 256x256 is a pretty good size that you can trust most people to be able to support with their gfx hardware without causing things to break. So that means, if you really want to be backwards compatible and reach as many people as possible with the same code, you'd have to break things down into 256x256 `tiles`, ie lots of smaller textures rather than one big one.

As far as texture sizes go, powers of two are generally faster to deal with in binary and with simple math than unusually sized dimensions. Also in earlier OpenGl, it only supported square textures. In higher versions of OpenGL they added support for rectangular textures, but it's not a part of the OpenGL 1.2 basic command set supported by BlitzMax. You'd have to use `extensions` to the OpenGL system, which may or may not be supported by all gfx cards and platforms.

So, if you try to turn a pixmap into an image, or load an image, or create an image, and you provide dimensions that are not an exact multiple of 2, from 64 upwards, BlitzMax has no other choice but to use the `next biggest` power-of-two size so that your image can fit within it. And yes it wastes the extra memory space. In particular, a 640x480 image has to be stored in a 1024x1024 texture which wastes a lot of space.

To draw an image, which is actually meant to be smaller than the texture that it is stored in (like 640x480), BlitzMax just creates a quad (two triangles) on the screen and tells it that the coordinates within the texture are whatever the corners of the image is, so that the wasted space part is ignored. You end up only seeing the image you created and the wasted space is not displayed.

So you have to bear in mind that if you indirectly `cause` a texture to be used that is bigger than the image area that you want to work with, video memory is being wasted. Also bear in mind that especially older hardware does not support really big single textures, so like 2048x2048 and especially 4096x4096 may well not be supported on many systems.

Now, something that you want to try to do, if you can make or find routines that help you with it (I think there's something in the archives or other forums), you want to try to use any `wasted space` on a texture, to store other images, to use up the `real estate` as much as possible. So, say you had small bullet images, you could probably store, say, 16 of them on a 64x64 texture. Then there's no wasted space and it's not having to make a whole 64x64 texture for every single bullet frame. Then, you just have to make a textured quad with the portion of the texture for whatever relevant image you want displayed, with the appropriate `texture coordinates` within the texture. Again, those codes/forums may help.

You also want to bear in mind that in order for OpenGL to use an image to draw anything with, ie to put it on the screen, it has to be usually transferred from main memory to graphics memory. That transfer is done with the CPU as a basic memory copy - except it also involves some rearranging of the data to turn it into the correct format/size etc. That tends to be time intensive, and certainly slower than how the graphics card usually draws stuff. The same is true of DrawPixmap - it's using the CPU to draw `over` the graphics bus (between main mem and video mem), and generally speaking the graphics bus is somewhat slower than the speed at which the gfx card can draw stuff.

So you want to try to limit transfers between main memory and graphics memory as much as possible. If there is some way that you can only use OpenGL as a `display system`, rather than using it to draw things that you want to read back in, that will help with your speed. You may then have to create some other routines (or find some) that does some drawing in main memory, to pixmaps or arrays or whatever, which you can then read from, with the CPU, much more efficiently than if you tried to get that information from video memory. The thing is, if you wanted to `download` image data from video memory to main memory, such as with GrabPixmap, it again goes over the graphics bus which is slow, and using the CPU to main memory, which is slower than the gfx-card's drawing speed by quite some times.

Also you would probably want to try to avoid having to `create` new images (textures) on the fly, because it has to do a memory allocation and initialization, plus probably an upload of data over the bus or a grabbing of data from the backbuffer. That takes quite some time. If you can set up a static/dummy texture to keep, over time, and then re-upload to it or re-grab to it, that is faster than making whole new ones. To do this you probably will have to bypass Max2D and work with OpenGL directly.

Because the image being displayed/drawn by OpenGL is somewhat separated from the CPU and main memory, off in video memory on the gfx card, you generally want to limit having to cross that bridge as much as you can. They have things like display lists and vertex arrays which are more advanced ways to avoid constantly `uploading` stuff. Also if you want to `sense` the images you create, in some way, like reading pixels, detecting pixel collisions, searching for colors, or drawing some kind of `permanent change` to a backdrop, you generally run into some problems. Reading data, with the CPU, means again that data has to be passed over the graphics bus which is slow. If you are going to be sensing the presence of boundaries with some kind of pixel reading, it's probably going to be faster to read that in main memory FROM a main-memory-based pixmap. Especially if you are going to be reading a lot of pixels, or doing full-screen changes to pixels in a way that you can't do on the gfx card, you should do it to a main-memory pixmap.

So you might want to think about what kind of engine you are going to make. If you are only going to use OpenGL as an OUTPUT system, a `rendering library`, and you have everything else you need stored in main memory for detecting for example a tile map or image boundaries, etc, then it should work pretty efficiently and effectively. If you want to get INPUT from the images you draw, or you want to take the backbuffer and read from it - ie to make a permanent change to a background or something, then you really ought to think of other ways to get the information that you want - preferably by keeping a copy of your bitmap/game world in a pixmap and using that for reading.

What you could do is then just think of OpenGL as a display device, and as you `scroll` the display, upload only the smallest amount of `new pixels` at the edges of the scroll area each frame. You can use the `offline` bitmap to store your permanent changes or destructed landscapes or whatever, and just upload those in small chunks (tiles) to the gfx card for display. That's one way of doing it.

If you don't need to store big changes, you could just keep your static background in one or more textures but that does mean using up a lot of video ram. Bear in mind that older or cheaper gfx cards generally have less video ram. Mine has 64mb for example but my other ibook only has 2mb graphics mem (it doesn't have hardware acceleration very much so it uses a software openGL device using main memory for textures - and is really slow).

I hope that sheds some more light on it.