tile storing methods

Started by
19 comments, last by smokes 23 years, 9 months ago
hi im still working on this tileengine.. its pretty nice by now, created a little GUI to go with it and such.. until now I''ve been using a Tile class which loads a tile from a bmp file to a surface included in the class.. the class stores the filename so reloading can be done after a task switch etc.. I don''t like several hundred little tile files.. so im planning on developing a little nice TileSet class.. my question concerns storage methods.. in the tutorials they usually load one bitmap containing all the tile set to a surface, store the RECTs and blit directly from that surface.. or they use som sort of tileset file, in which the tiles are stored with a tile header and then the actual tile data, I guess their tileset class blits all the tiles (using bitblt or something) to one big surface and then use the above methods (with rects).. using dxsurface->Blt (or BltFast) to blit from the surface.. buuuut.. I''ve done some calculations.. and if I for example wants 256 tiles to be the maxtiles in each set.. I will need a surface (I use 64x64x16bit tiles) 2.097.152 bytes large.. I have a 4mb card (lame I know).. but say you use the program on a 2 mb card.. well the surface cannot be stored in vidmem.. so dx will place it in sysmen.. this sucks.. because then you won''t take advantage of the vidmen!!.. ALL the surface will be created in sysmen.. but if I on the other hand.. use the tileset file.. and loads the tileset to sysmen.. from there create one surface per tile.. it would take advantage of the vidmen available.. because if the giant surface is just one byte more than available vidmen it will be created in sysmen.. thereby not using the vidmen to just place SOME of the tiles in it.. (hope im not confusing you too much.. kindda tired :-).. but if you allocate the 255 tiles to 255 surfaces.. and the user then performs a taskswitch.. simple.. restore all the surfaces.. but the reload.. would be to slow to load all the tiles from disk.. but If I stored the entire tileset in mem.. and memcopied to the surfaces... but it would it not be bad programmering because I would have to same data in mem twice?!? help me out on this one you experienced tilers *lol* perhaps by telling me how YOU do it :-)
Advertisement
In all honesty, my computer has 16megs or vidmem so I can still load all of the images into it and so havent really run into that problem yet on my home-pc, but i have tested my game on comps with only 2megs of vidmem and lower and I get extremely low frame rates, like 10fps in 1024x768x16, which is unnoticable except when using the smooth scrolling. As for trying to load as much of it as you can in vidmem, thats best with small files, cause if you have a large image file as you mentioned and its just slightly to large, the whole thing will go into sysmem, but also 1 large file is very nice and convient, but you might want to use stuff like civ2 does, dont put all tiles/units/objects ect.. all in 1 image, make a single image for the most used tiles and nothing else, and then load that first so it gets into vidmem, and then load the other less used tile images. Otherwise there isnt much you can do, a crappy computer is a crappy computer and can only play old crappy games.

As for task switching, i still lose all my surfaces and I am curious as to what the windows message is for that so I can
restore them.

Possibility
ironically, i quit smoking two and a half days ago.

there are any number of things you can do to maximize performance of your tileset class. however, before you do any of them, you need to know if it is a necessary change, and measure how much performance is enhanced. if a greater speed increase can be accomplished elsewhere, do that instead.

putting something into video memory isnt always the most ideal conditions. Yes, blitting from sysmem to vidmem is costly, and you don''t want to do it more than you have to. however, sysmem to sysmem is pretty fast, if you cant get vidmem to vidmem, why not try that?

here''s an idea. keep a var (either in the tileset class, or global, or whatever) somewhere that keeps track of a "blit state". this will hold one of two values... BLIT_VIDMEM, or BLIT_SYSMEM.

when you try to load your tileset, first attempt to load it into vidmem. if it is successful, you set your blit state var to BLIT_VIDMEM

if it fails to be created in vidmem, create it in system memory intead, set your blit state var to BLT_SYSMEM. also, when this happens, create a surface in sysmem that is the same size as your screen.

here is some rendering pseudocode for you:

if(blitstate==BLT_VIDMEM)
RenderToBackBuffer()
else//blitstate==BLT_SYSMEM
{
RenderToOffscreenSurface();
BlitOffscreenSurfaceToBackBuffer();
}


with this, if your tileset is in vidmem, it will just render to the backbuffer, since vidmem->vidmem is best for transfers. if your tileset is in sysmem, it renders it to the offscreen surface you created in sysmem. this is much better than doing all of those blits from sys to vid. finally, you blit once and only once from the offscreen surface to the back buffer.

on systems with a lot of vidmem, it''ll run to its best capacity, but on a system without much vidmem, it wont just drag alot, since you are making the best for what you have.

Get off my lawn!

to TAN> thank you :-).. but is the idea of "a surface per tile" bad? will it cause performance problems? overhead? I probably only gonna need 200-300 tiles on this project.. probably less :-).. cause'' im actually not making a game.. im making an advanced chat/virtual community :-)

to Possibility:
cool this is the first time I (perhaps) are able to help someone on this forum :-).. this goes for taskswitching:
in your winproc.. check for the WM_ACTIVEAPP

LRESULT CALLBACK WinProc(HWND hwnd, unsigned msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_ACTIVATEAPP:
{
Active = wParam; // Active is a global BOOL
}
}

with this code Active is only true when the app has FOCUS.
oki if we assume you call your GameMain() in the while-loop in winmain, do this:

while(Active)
{
...
GameMain();
...
}

this will prevent GameMain() from being executed when the application hasn''t got focus.
oki when user presses alt tab Active is set to FALSE and gameloop execution is paused.. but now the user activates the game again.. all surfaces are lost.. so all you got to do is to check for the DDERR_SURFACELOST return code (errorcode) in the first function which calls any DX calls capable of returning the code.. then you call RestoreAllSurfaces() on your DirectDraw object (assuming you''re coding for DX7, otherwise you have to loop trough all surfaces and use the Restore() method on each)
if RestoreAllSurfaces() returns DD_OK just reload all your bitmaps (good idea to implement an easy way to do this in your design :-).. I have a function in each of my classes which contain a surface with a loaded bmp on it called Reload()..

quote:Original post by smokes

cool this is the first time I (perhaps) are able to help someone on this forum :-).. this goes for taskswitching:
in your winproc.. check for the WM_ACTIVEAPP



Sorry if this is a stupid question or a stupid idea but: Is the WM_ACTIVATEAPP recieved before or after the surface(s) is lost?

I thought that maybe you could "backup" the tile surfaces to system memory just before the surfaces was lost. When your game became active again you could then restore them without the need to read from the disk and free the memory used by the backup again.

But then again this maybe used up too much memory? It may be needed by the program you are task switching to?

Regards

nicba
A little off topic but, congrats to Tanstaafl for quitting smoking.

Yay!
Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

smokes...

the idea of one surface per tile isnt necessarily a "bad" idea, but it can make tile management more of a problem, especially if you are going to come up with a "most commonly used" tile management algorithm, where the most heavily used tiles are in vidmem, and the lesser used tiles are in sysmem. this kind of thing can quickly turn into a resource management nightmare.

possibility & nicba...

yes, the WM_ACTIVATEAPP is the way to go, however, you probably want to use a scheme something like the following:

//globals
bool bActive=false;//true when this is the current app
bool bInitialized=false;//true when the data has been initialized

...(somewhere in the windowproc)

case WM_ACTIVATEAPP:
{
if(wParam)
{
bActive=true;
if(bInitialized)
{
RestoreSurfaces();//user defined function
}
}
else
{
bActive=false;
if(bInitialized)
{
SaveSurfaces();//user defined function
}
}
}break;

notes:
bInitialized is set to true during your initialization section, and it being true indicates that all of your dx objects have been instantiated.
bActive is used to suspend execution when the application is not active
RestoreSurfaces() should both restore the surfaces and the contents thereof (only necessary for vidmem surfaces)
SaveSurfaces() is something i havent tested, but you should be able to backup the contents of vidmem to sysmem right before the application loses focus. (by setting up some surfaces in sysmem temporarily and then destroying those surfaces in RestoreSurfaces()

Get off my lawn!

The way I restore surfaces isn''t like that approach at all, and works rather well, so I guess I Should share it with you fine folks here at gamedev.

With that approach, the function RestoreSurfaces() would have to go through every image you have and restore it, which I assume means you would have to add an image->Release() line every time you have a new item.

The way I have it set up is like so. I have a sprite class with all the basic functions, including Draw() and Restore() (and Load()) When you load a file it saves the filename in a filename variable for you.

Now in the Draw function, I have a call to Blt or BltFast()

if the blit routine doesnt return DD_OK, I check to see if it returned DDERR_SURFACELOST, if that is what it returned (Which is what it WILL return if you minimized and returned) it calls its own Restore() function and presto.

So, with this method, you dont even have to care about restoring your surfaces, it''ll take care of it for you by itself which is what I like about it. Load all the images you want, PLUS it''ll only restore surfaces that need restoring rather than restoring all surfaces no matter what.

So what do you think?



ByteMe95::~ByteMe95()
ByteMe95::~ByteMe95()My S(h)ite
ByteMe95 - That approach works well until you deceide to use resource files. Then you need to store two names, 1.) the name of the resource file and 2.) the name of the graphics file within the resource file.

Also, if your surface''s graphics are dynamic, maybe you add footprints or skid marks, etc. to the surface as the game is played. Then restoring from the original file does not work so well because you wipe out all the dynamic stuff.

I implemented a save/restore system in CDX just as described by TANS except it saves the surfaces as BMPs on the hard-drive. This is not ideal because of I/O is slow. I plan to make it an option to save to memory or disk. Saving to disk can be helpful for debugging because you can open the saved BMP and you are looking at the contents of your surface. Another option I plan on adding is a flag that says if you want system memory surfaces saved as well.

All the code is in CDX on sourceforge.com, and it is free!

hebertjo
hebertjo
Byteme>>> I currently use your approach.. sort of.. RestoreAllSurfaces doesn''t involve me creating a loop iterating trough ALL surfaces and calling dxsurface->Restore() on them.. RestoreAllSurfaces is a DX(7?) function that does that for you.. you call it on the directdraw object and since this object is used in creating the surfaces it can obviously restore again :-). but hebertjo is right.. the bitmaps should be restored from sysmen.. not disk.. don''t expect user to be waiting for several minutes when all they want to do is check their ICQ''s :-) (example)

This topic is closed to new replies.

Advertisement