Sign in to follow this  
ErikPeeters

LOST!

Recommended Posts

Hi all, I'm totally lost! I have been trying (for months now) to make an isometric textured tiles map in OpenGL consisting out of 100*100 tiles, but some how it has a huge video memory drain. This way I will not be able to animate other tiles because of this drain. How can a game like SimCity 2000 or Transport Tycoon work so quick with such large maps? What am I doing wrong? Can somebody help me please, perhaps by giving some guidelines or examples? I would realy appreciate it. Thanks in advance, - Erik

Share this post


Link to post
Share on other sites
Start by describing what are you doing at the moment as well as more detailed description of the manifestation of the problem, and by pointing out what have you tried so far to locate the problem.


Without any inormation no one can help you.

Share this post


Link to post
Share on other sites
Sim City and Transport Tycoon(1) use a system called 'dirty rectangle' whereby only the parts of the screen that change are redrawn. This massively reduces the drawing overhead. When an object visually changes (moves, animates, etc...) it calculates the screen rectangle it occupies(2) and adds this rectangle to a list of rectangles. In the drawing phase, this list is scanned for overlaps and clipped to the screen area and a minimal rectangle list is created. These rectangles are then redrawn. The ability to redraw arbitrary sized rectangles allows the picture-in-picture effect to work without the need for any special code. This is also how the Windows GUI works (and probably all the other GUI OSes).

Skizz

(1) I know this for a fact because I converted the original TT to the Mac (and did a PS1 version as well). It wasn't nice, the PC version was 100% assembler. It was well structured (OO infact), but quite perverse in places - the rendering code was a huge macro that was instantiated for each zoom level, the macro parameters affecting the way the drawing code worked.
(2) In TT it stores the rectangle in 'world space' and the rectangle list is scaled depending on the zoom level.

Share this post


Link to post
Share on other sites
Hi guys, thanks!

I first make a struct called TILE, in which I have some X and Y positions, and after that a struct called MAP.
In this struct MAP I have declared a TILE instance


typedef struct tagMAP
{
TILE Tile[101][101];
} MAP;

MAP m_map;



Then in the method DrawGLScene() I do the following:


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix

glTranslatef(0.0f, 0.0f, -5.0f);

glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND);

float fXPos = 0.00f;
float fYPos = 0.00f;

for(int nCurRow = 0; nCurRow < 101; nCurRow++)
{
for(int nCurColl = 0; nCurColl < 101; nCurColl++)
{
fXPos = (m_map.Tile[nCurRow][nCurColl].fXPos + m_map.Tile[nCurRow][nCurColl].fXOffset);
fYPos = -(m_map.Tile[nCurRow][nCurColl].fYPos - m_map.Tile[nCurRow][nCurColl].fYOffset);

glBlendFunc(GL_ONE, GL_ONE);
glBindTexture(GL_TEXTURE_2D, texture[m_map.Tile[nCurRow][nCurColl].nImageNr]);
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.1f + fXPos + map_xpos,-0.1f + fYPos + map_ypos, jumpZoom);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.1f + fXPos + map_xpos,-0.1f + fYPos + map_ypos, jumpZoom);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.1f + fXPos + map_xpos, 0.1f + fYPos + map_ypos, jumpZoom);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.1f + fXPos + map_xpos, 0.1f + fYPos + map_ypos, jumpZoom);
glEnd();
}
}

glDisable(GL_BLEND); // Disable Blending
glEnable(GL_DEPTH_TEST);



fXPos and fYPos are the x, y positions of the tile on the screen.
map_xpos and map_ypos are set by mouse moves and arrow keys.
jumpZoom are three different zoom levels controled by the 1, 2 and 3 key.

I will post my entire code if it will help....

- Erik

Share this post


Link to post
Share on other sites
Obvious things to sort out:
1) Move the glBegin, glBlendFunc, glBindTexture and glEnd outside the loops. The trick here is to do:

for each tile
get texture
add tile to a map indexed by texture

for each texture
glBegin
glBindTexture
glBlendFunc
for each tile
draw tile
glEnd

The begin/bind/end overhead is very large.
2) Use one dimensional arrays rather than two:

typedef struct tagMAP
{
TILE Tile[101*101];
} MAP;

and iterate through the map:

for (TILE *tile = m_map.Tile ; tile != &m_map.Tile [101*101] ; ++tile)
{
// process tile!
}

Also, write a function to convert x,y into offset:

int XYToIndex (int x, int y)
{
return x + y * 101;
}

3) Only process visible tiles. Not doing something is always quicker. Taking the idea in point (1):

for each tile
if tile is visible
get texture
add tile to a map indexed by texture

That should give you plenty to work with.

Skizz

Share this post


Link to post
Share on other sites
I've got an abandoned project having isometric tiles. I've started to draw the ground from C&C tiberian sun. This sourcecode can also detect visible tiles and organize textures used by the isometric geometry. The drawing module can simply handle maps like 256x256 or higher.
You can have my source related to this if you like.

I'd planned to have a procedural terrain generation. Sorry, that I can't give away the genertor itself, but you can have my converter which converts a float based heighmap(you can simply create with fractals like I do) into tilebased heighmap. Some problems were managed really tricky (also borders a.s.o.). And it's a pitty to throw it all away.

Share this post


Link to post
Share on other sites
Yeah sure, I would like very much to have a look into that sourcecode, thanks!

I guess that I can detect if tiles are visible by comparing the x, y positions by the view width and height (look if they fall outside the screen edges)?
But when I have my map zoomed out I suppose I have to draw it entirely?

I will adapt my code to the changes suggested above...

Thank you,

- Erik

Share this post


Link to post
Share on other sites
// clip tiles out of screen
if(ty < -YTILE || tx < -XTILE || //negative limit
tx > CLIENTX+XTILE || ty > ( CLIENTY + YHALF )) // positive limit
continue;


thats how i clip the offscreen tiles, tx and ty are the center tile positions on the screen, so I simply skip the ones not inside the client area. There isnt a huge need to do the dirty region stuff now unless your really zoomed out and your viewing a 256x256 map. I recommend Isometric Game Programming with DirectX 7.0 by Ernest Pazera if you wanna get really deep into the dirty region updating stuff...he covers it well.

Share this post


Link to post
Share on other sites
I've uploaded the ressources for you:

www.razorjack.de/isometric.zip

The draw routine can be found in:
GroundPlane.cpp / world.h (Header for it)
Every other file is used for script loading + parsing and map preparing.

Some information for you:

If you notice any undrawn tiles at the top edge of the screen, you can enlarge the screen rect in the draw routine. That's all what I didn't done.

The map looks nice because I have mostly 4-8 textures for each ramp type.
There are still some ramp textures I haven't imported from C&C and which will be skipped (You'll see gaps there). You can add these into the script.

A ramp type is coded by 4 integers. If you can't find out how it works, you can just ask me.

My email is: me@razorjack.de
Good luck and have fun.

Share this post


Link to post
Share on other sites
Hi Razorjack,

thank you very much for the code. I can't compile it yet, but I hope I figue out how to...:)
I can however see how to configure the map.

If I run into any problem I'll ask you, thanks again.

- Erik

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this