Optimizing Tile Map Drawing

Started by
6 comments, last by pcvii 14 years, 8 months ago
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==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,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,&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]
Advertisement
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.
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.
oh yeah TY for the reply.
I'm gonna play with this to try figure out the calculations
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 tilesfloat sc = ltTiles.Scale(); //Current Scaleint 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 bysize)* //Tile Sizesc+ //Adjusted for Scale(float)top*sc + //Top Offest adjusted for Scale(iwheight/2)); //Move to Center of Screen: Window Height Divided by 2if(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 -Spacerow = (((-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 alwayscol* //Col Number Multiplied bysize* //Tile Sizesc+ //Adjusted for Scaleleft*sc+ //Left Offest adjusted for Scale(iwwidth/2)); //Move to Center of Screen: Window Width Divided by 2if(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 -Spacecol = (((-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 anymoreif(MAP!=280) //280 is a transparent unwalkable tileltTiles.Draw(MAP,y,x,0); //Draw}}EndDrawing ();


[Edited by - pcvii on August 20, 2009 2:57:27 PM]
Someone said I should use a texture atlas. I think I should look into it. Anyone know a good example of using UVAtlas from directx9?
Hi

Look at my home page for project "Ruff'n'Tumble". Have a look at the source code (line 140) for rendering layer in my tile map.
- Iliak -
[ ArcEngine: An open source .Net gaming framework ]
[ Dungeon Eye: An open source remake of Eye of the Beholder II ]
That looks pretty nice. Thanks for the link.

This topic is closed to new replies.

Advertisement