slow isometric sdl drawing

Started by
6 comments, last by Drew_Benton 19 years, 4 months ago
hi i put this code together quickly, but it seams to run reallly slow. im not really doing anything that processor intensive. when i get to an edge of the map it runs fast, obviously suggesting that something in the drawing code is slowing it down, but as im new to this, i cant see what. also when i add the fullscreen flag, nothing is drawn. thanks in advance heres the code:

#include <stdio.h>
#include <stdlib.h>

#include "SDL.h"

SDL_Surface *grass;
SDL_Surface *stone;

SDL_Surface *screen;

int tileW = 36;
int tileH = 18;
int mapX = 60;
int mapY = 10;
int movement= 2;

//ignore the way this is done, just set up to test a couple of tiles.
int mapArray[100][100];

void Slock(SDL_Surface *screen)
{
  if ( SDL_MUSTLOCK(screen) )
  {
    if ( SDL_LockSurface(screen) < 0 )
    {
      return;
    }
  }
}

void Sulock(SDL_Surface *screen)
{
  if ( SDL_MUSTLOCK(screen) )
  {
    SDL_UnlockSurface(screen);
  }
}

SDL_Surface * ImageLoad(char *file)
{
  SDL_Surface *temp1, *temp2;
  temp1 = SDL_LoadBMP(file);
  temp2 = SDL_DisplayFormat(temp1);
  SDL_FreeSurface(temp1);
  return temp2;
}

int InitImages()
{
  grass = ImageLoad("grass.bmp");
  stone = ImageLoad("stone.bmp");
  return 0;
}



void DrawIMG(SDL_Surface *img, int x, int y)
{
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
  SDL_BlitSurface(img, NULL, screen, &dest);
  SDL_UpdateRects(screen, 1, &dest);
}

void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2)
{
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
  SDL_Rect dest2;
  dest2.x = x2;
  dest2.y = y2;
  dest2.w = w;
  dest2.h = h;
  SDL_BlitSurface(img, &dest2, screen, &dest);
  SDL_Flip(screen);
}

void DrawMap(){

     Slock(screen);
     
     SDL_SetColorKey(stone, SDL_SRCCOLORKEY, SDL_MapRGB(stone->format, 255, 0, 255));
     SDL_SetColorKey(grass, SDL_SRCCOLORKEY, SDL_MapRGB(grass->format, 255, 0, 255));

     for(int j = 0; j < 100; j++){
          for(int i = 0; i < 100; i++){
               if(mapArray[j] == 0){
                    if(((tileW/2)*(j-i))+mapX < (640+tileW) && ((tileW/2)*(j-i))+mapX > (0-tileW)){
                         if(((tileH/2)*(j+i))+mapY < (480+tileH) && ((tileH/2)*(j+i))+mapY > (0-tileH)){
                              DrawIMG(stone, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
                         }
                    }

               }
               else{
                    DrawIMG(grass, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
               }
          }
     }

     Sulock(screen);
}

int main(int argc, char *argv[]){


     Uint8* keys;

//ignore the way this is done, just set up to test a couple of tiles.
     mapArray[1][1] = 1;
     mapArray[2][1] = 1;
     mapArray[4][1] = 1;
     mapArray[50][50] = 1;
     mapArray[40][35] = 1;
     mapArray[50][40] = 1;
     mapArray[40][35] = 1;

  if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 )
  {
    printf("Unable to init SDL: %s\n", SDL_GetError());
    exit(1);
  }
  atexit(SDL_Quit);

  screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF|SDL_ANYFORMAT);

  if ( screen == NULL )
  {
    printf("Unable to set 640x480 video: %s\n", SDL_GetError());
    exit(1);
  }

  InitImages();
  DrawMap();

  int done=0;

     while(done == 0){
          SDL_Event event;

          while ( SDL_PollEvent(&event) ){

               if ( event.type == SDL_QUIT )  {  done = 1;  }

               if ( event.type == SDL_KEYDOWN ){
                    if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; }
               }
          }
    keys = SDL_GetKeyState(NULL);

    if ( keys[SDLK_UP] ) { 
         mapY = mapY-movement; 
    }
    if ( keys[SDLK_DOWN] ) { 
         mapY = mapY+movement; 
    }

    if ( keys[SDLK_LEFT] ) { 
         mapX = mapX-movement; 
    }

    if ( keys[SDLK_RIGHT] ) { mapX = mapX+movement; 
    }

    DrawMap();


 }

  return 0;
}

edited by evolutional: Source tags! See the FAQ for more information [Edited by - evolutional on November 25, 2004 5:36:36 PM]
Advertisement
Quote:Original post by r0bbb

screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF|SDL_ANYFORMAT);

this will not probably help much but use SDL_HWSURFACE instead.. And use [ source lang="cpp"] or tags<br>
Ad: Ancamnia
Hi! Your code is probabally slow because of your draw function:

void DrawMap()
{
// Slock(screen); format, 255, 0, 255));
SDL_SetColorKey(grass, SDL_SRCCOLORKEY, SDL_MapRGB(grass->format, 255, 0, 255)); (0-tileW))
{
if(((tileH/2)*(j+i))+mapY (0-tileH))
{
DrawIMG(stone, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
}
}
}
else
{
DrawIMG(grass, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
}
}
}
// Sulock(screen); <---- NOT NEEDED
}

Once you make those changes, you should see IMMEDIATE improvments. furthermore, you should take a look at enabling opengl blitting in your game/app so it is faster and looks better. If you have any questions or comments, email me, dr3w_b3nton AT hotmail.com
ok sorry, none of my comments made it to the final post :/ and I cant get my login to work so ill try this again, if you need better clarifcations email me por favor:

Hi! Your code is probabally slow because of your draw function:

void DrawMap()
{
Slock(screen); **NOT NEEDED**
** SDL_SetColorKey(stone, SDL_SRCCOLORKEY, SDL_MapRGB(stone->format, 255, 0, 255));
SDL_SetColorKey(grass, SDL_SRCCOLORKEY, SDL_MapRGB(grass->format, 255, 0, 255)); ** ONLY CALL THESE FUNCTIONS ONCE AFTER YOU LOAD THE IMAGES **

**YOU DONT NEED TO DRAW 100,000 tiles EACH time, limit yourself to the screen resolution / tile dimenstions, ex: 640x480 screen and 32x32 tiles, you will only need to draw '640/32' x '480/32' tiles.
for(int j = 0; j (0-tileW))
{
if(((tileH/2)*(j+i))+mapY (0-tileH))
{
DrawIMG(stone, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
}
}
}
else
{
DrawIMG(grass, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
}
}
}
// Sulock(screen); ---- NOT NEEDED ----
}

Once you make those changes, you should see IMMEDIATE improvments. furthermore, you should take a look at enabling opengl blitting in your game/app so it is faster and looks better. If you have any questions or comments, email me, dr3w_b3nton AT hotmail.com
You also have a LOT of redundant code.

tileW/2 & tileH/2 is used multiple times.
Just create an int for each and save the results there.

Same with j+i and j-i, 640+tileW and 480+tileH, 0-tileW and 0-tileH (these 4 really only need calculating once). Sure not that expensive but if you do it 100x100 times it sums up.

the data in this code
DrawIMG(stone, ((tileW/2)*(j-i))+mapX, ((tileH/2)*(j+i))+mapY);
has already been calculated in the ifs.. if you use the variables you would not need to calculate this stuff.
Same for the grass drawing.

General tip:
Make your code readable, then make it fast.
Go through what you are doing step by step and try to avoid such long expressions.

Had you gone through it step by step and created variables for each you could have avoided above problems.

Here is how I might do it.
WARNING: dumb variable names ;)
// only need these onceint half_tileW = tileW/2;int half_tileH = tileH/2;int screen_width_P_tileW = 640+tileW;int screen_height_P_tileH = 480+tileH;// variables outside the loop so they only get initialized onceint half_tileW_jPi = 0; // replaces half_tileW*(j+i)int half_tileW_jMi = 0; // replaces half_tileW*(j-i)int half_tileH_jPi = 0; // replaces half_tileH*(j+i)int half_tileH_jMi = 0; // replaces half_tileH*(j-i)int half_tileW_jMiPmapX = 0; // replaces half_tileW_jMi + mapXint half_tileH_jMiPmapY = 0; // replaces half_tileH_jPi + mapYfor(int j = 0; j < 100; j++){          for(int i = 0; i < 100; i++)          {               // put thise here because you will need them everytime               half_tileW_jMi = half_tileW*(j-i);               half_tileH_jPi = half_tileH*(j+i);                              half_tileW_jMiPmapX = half_tileW_jMi + mapX;               half_tileH_jPiPmapY = half_tileH_jPi + mapY;               if(mapArray[j] == 0)               {                   half_tileW_jPi = half_tileW*(j+i);                   half_tileH_jMi = half_tileH*(j-i);                   // this is how I format my code                   if( ( half_tileW_jMiPmapX ) < screen_width_P_tileW &&                       ( half_tileW_jMiPmapX ) > -tileW )                   {                       if( ( half_tileH_jPiPmapY ) < screen_height_P_tileH &&                           ( half_tileH_jPiPmapY ) > -tileH )                       {                           // calculations only done once, so we keep                           DrawIMG(stone, ( half_tileW_jPi + mapX, half_tileH_jPi + mapY);                       }                   }               }               else               {                    DrawIMG(grass, (half_tileW_jMiPmapX, half_tileH_jPiPmapY);               }          }     }
Remove the SDL_UpdateRect and SDL_Flip from both the versions of DrawIMG. You're syncing to a screen refresh on EVERY TILE, even if that tile is off-screen.

Instead, do the SDL_Flip() at the end of DrawMap.

Also, do not lock the screen. (Slock/Sulock)
You only need to lock a surface if you require pixel-level access to it.
SDL_BlitSurface locks and unlocks the surface if necessary, and if it isn't necessary... it might slow it down
thanks a lot travis that sorted it! great stuff.

thanks eveyrone for your help

I can also say you should use OpenGL blitting. Its like giving SDL steriods!

This topic is closed to new replies.

Advertisement