Sign in to follow this  

Optimizing Tile Map Drawing

This topic is 3040 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

VC++ Express 2008 Direct X 9 SDK SDL 1.2 (used as back-end for events and such) <-- I have used SDL the most. I have an Array of 256x256 tile ids for the map. 65536 total tiles ids Each Tile is 16x16 Stored in a one dimension array; Each id matches up to the Array of Textures I have. Though when the screen is full of these little textures things can get slowed down a lot. I'm trying to figure out the best way to optimize this. I kinda been looking at example code here and there to get some thing started so I'm still very inexperienced with Direct3D 9.
for(Uint32 i=0;i<65536;i++)
{
if(MAP[i]==280)continue;
float sc = ltTiles.Scale();
int space = ceil(16.0*sc);
int x = ceil(((i%256)*16.0*sc+left*sc)+(iwwidth/2));
int y = ceil(((i/256)*16.0*sc+top*sc)+(iwheight/2));
if(x>iwwidth+space || y>iwheight+space) continue;
if(x<-(space) || y<-(space)) continue;
ltTiles.Draw(MAP[i],y,x,0);
}

int D3DLargeTexture::Draw(int i,int top,int left,float angle)
{
if(i<0 || i> irows*icols)return 0;
int size = ceil(isize * fscale);
RECT sCords;
sCords.top = top;
sCords.left = left;
sCords.bottom = size + top;
sCords.right = size + left;
Blit(d3dtextures[i],&sCords,angle);
return 1;
}

void Blit(IDirect3DTexture9* texture, RECT* rDest, float rotate)
{
    float X;
    float Y;
    D3DXMATRIX matTranslation;
    D3DXMATRIX matScaling;
    D3DXMATRIX matTransform;
    
    //Get coordinates
    X = rDest->left - (float)(present_parameters.BackBufferWidth) / 2;
    Y = -rDest->top + (float)(present_parameters.BackBufferHeight) / 2; 

    //Setup translation and scaling matrices
    D3DXMatrixScaling (&matScaling, (float)(rDest->right - rDest->left),
        (float)(rDest->bottom - rDest->top), 1.0f);
    D3DXMatrixTranslation (&matTranslation, X, Y, 0.0f);
    matTransform = matScaling * matTranslation;

    //Check if quad is rotated
    if (rotate)
    {
        D3DXMATRIX matRotate;

        //Create rotation matrix about the z-axis
        D3DXMatrixRotationZ (&matRotate, rotate);

        //Multiply matrices together
        matTransform *= matRotate;
    }

    //Draw the quad
    direct3D_device->SetTransform (D3DTS_WORLD, &matTransform);
    direct3D_device->SetTexture (0, texture);
    direct3D_device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
}


[Edited by - pcvii on August 20, 2009 2:51:10 PM]

Share this post


Link to post
Share on other sites
First off, let me say that I am in no way familiar with SDL, or optimizing with D3D. However, I did notice one thing that stood out to me:

In your main (first) loop, you essentially loop 65536 times for each frame (or update, or whatever). That's a lot of unneeded looping. Try to think of what a tile map really is: a 2-dimensional array. Only a certain area will fit on (or affect whats on) the screen, so figure out what that area is before you do a loop. Then, just loop through those tiles within that area. This should cut out a lot of unneeded loops.

I find it easier to tackle these problems with a piece of graph paper. Come up with a smaller scenario (for example, a 10x10 tile map with a 'window' of only 5x5), and graph it all out. Develop your algorithm out of that.

Also, you can try cleaning up some code for readability, it will really help in the long run (when you come back to your code later). For example, the lines:
int x = ceil(((i%256)*16.0*sc+left*sc)+(iwwidth/2));
int y = ceil(((i/256)*16.0*sc+top*sc)+(iwheight/2));

are not very clear to me what they do. Too many parenthesis, reminds of lisp ;)
Readable code is more important than faster code.

Share this post


Link to post
Share on other sites
I like that reply it got me thinking. Your right I don't need to loop through every tile. I can use a calculation to find out what tiles would be on the screen first and only draw those.

And I'll try to make my code a little bit more readable.

Share this post


Link to post
Share on other sites
Well this seems to work a bit better I had trouble wrapping my head around the math. Turns out I was doing my algebra wrong when solving for Col and Row. Heh

I Kinda like how it is working right now. Though if you zoom out all the way it still takes for ever to draw all the tiles. But thanks to your suggestions It's at least working well when your zoomed in normal. If anyone else has some optimization Ideas I'm all ears.

BeginDrawing ();
int x,y,size;
size = 16; //Size of tiles
float sc = ltTiles.Scale(); //Current Scale
int space = ceil(16.0*sc); //Extra Space (Room for Error)
x=0; //Calculated Left Position where the tile will be drawn.
y=0; //Calculated Top Position where the tile will be drawn.
for(Sint16 row=0;row<256 && row>=0;row++)
{
y = ceil( //Round UP always
(float)(row* //Row Number Multiplied by
size)* //Tile Size
sc+ //Adjusted for Scale
(float)top*sc + //Top Offest adjusted for Scale
(iwheight/2)); //Move to Center of Screen: Window Height Divided by 2
if(y<-(space)) //if this tile won't show on the screen.
{
//very similar to the previous calculation except you solve for Row where Y is -Space
row = (((-1) * ( (iwheight/2) + ceil(top*sc) + space ))/size)/sc;
continue;
}
else if(y>iwheight+space) break; //if this tile won't show on the screen.
for(Sint16 col=0;col<256 && col>=0;col++)
{

x = ceil( //Round UP always
col* //Col Number Multiplied by
size* //Tile Size
sc+ //Adjusted for Scale
left*sc+ //Left Offest adjusted for Scale
(iwwidth/2)); //Move to Center of Screen: Window Width Divided by 2

if(x<-(space)) //if this tile won't show on the screen.
{
//very similar to the previous calculation except you solve for Col where X is -Space
col = (((-1) * ( (iwwidth/2) + ceil(left*sc) + space ))/size)/sc;
continue;
}
else if(x>iwwidth+space) break; //if this tile won't show on the screen.
Uint32 i = col+row*256; //Find Tile ID
//if(x<-(space) || y<-(space)) continue; //shouldn't be needed anymore
if(MAP[i]!=280) //280 is a transparent unwalkable tile
ltTiles.Draw(MAP[i],y,x,0); //Draw
}
}

EndDrawing ();




[Edited by - pcvii on August 20, 2009 2:57:27 PM]

Share this post


Link to post
Share on other sites

This topic is 3040 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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