Thread: SDL lag when blitting

  1. #1
    Registered User
    Join Date
    Oct 2011
    Posts
    9

    SDL lag when blitting

    I'm pretty new to programming and I have spent some time learning to use SDL in order to make a simple 2d game.

    When I update the screen I blit the map/background and then I blit the moving things (player controlled character, etc) on top of it. I do this with a frame rate of 40 fps.

    The problem is that this seems to cause lag. I think it would make sense to remove the blitting of the map (since the map doesn't change in every frame) and just blit the map ones at the start of the game. However, this will make the character leave a trail of blitted images behind (since they are left on top of the map).

    My question is: is there a way to update the screen in a more efficent way, so the lag is reduced, without leaving the old images?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Each time you place a character on screen, you do
    - save the bitmap of where the character is going to be placed.
    - draw the character.

    Each time you erase a character (in preparation to draw it somewhere else), you do
    - copy the save bitmap back to the screen bitmap.

    Ideally, you to all of this on an off-screen buffer. When you're done updating the off-screen buffer, you can either
    - copy the whole off-screen to on-screen
    - just copy the modified rectangle(s)
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Oct 2011
    Posts
    9
    I think I understand what you mean, but I'm not sure how to actually implement it into the program. The erase part is what I have trouble with. How do I copy the bitmap back to the screen bitmap when it's already blitted and flipped?

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I would redraw the entire screen (via double buffering) and use layering or draw order to achieve what you want.

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    You could try speeding up the rendering a little bit; perhaps the lag won't matter so much if you have a faster frame rate. In terms of the SDL, if you create your video surface with the SDL_HWSURFACE video flag (to try to put the surface in hardware memory), you may get better performance. Double-buffering is quite simple, I believe you just have to initialize it and call SDL_Flip() when you want to swap the double buffers. Also make sure your bitmaps are the right format (using SDL_DisplayFormat or SDL_DisplayFormatAlpha) to match the screen; otherwise the SDL will be converting surfaces on the fly to the right depth-per-pixel, which is very slow!

    You can play around with updating only those rects that have changed; I tried this in one project (atlantis, see signature), and it really was more trouble than it's worth in my opinion. If you use double-buffering and a couple of coarse checks so that you don't do silly things like painting six maps on top of each other or painting all one-hundred offscreen sprites simultaneously, computers are fast enough these days that you can redraw the entire screen. As VirtualAce (whom I still think of as Bubba . . .) says, you can create some layers to render say the map to a surface and then blit that surface all at once whenever you need to redraw the screen. Give it a shot, see what happens.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Oct 2011
    Posts
    9
    Quote Originally Posted by dwks View Post
    You could try speeding up the rendering a little bit; perhaps the lag won't matter so much if you have a faster frame rate. In terms of the SDL, if you create your video surface with the SDL_HWSURFACE video flag (to try to put the surface in hardware memory), you may get better performance. Double-buffering is quite simple, I believe you just have to initialize it and call SDL_Flip() when you want to swap the double buffers. Also make sure your bitmaps are the right format (using SDL_DisplayFormat or SDL_DisplayFormatAlpha) to match the screen; otherwise the SDL will be converting surfaces on the fly to the right depth-per-pixel, which is very slow!

    You can play around with updating only those rects that have changed; I tried this in one project (atlantis, see signature), and it really was more trouble than it's worth in my opinion. If you use double-buffering and a couple of coarse checks so that you don't do silly things like painting six maps on top of each other or painting all one-hundred offscreen sprites simultaneously, computers are fast enough these days that you can redraw the entire screen. As VirtualAce (whom I still think of as Bubba . . .) says, you can create some layers to render say the map to a surface and then blit that surface all at once whenever you need to redraw the screen. Give it a shot, see what happens.
    Thanks for the advice!

    I tried to increase the desired frame rate in the code, but what happens is that the frame rate seems to drop to around 10-20 FPS no matter how high I set it.

    I've tried both SDL_HWSURFACE and SDL_SWSURFACE in the SDL_SetVideoMode, but it makes no visible difference when it comes to performance and frame rate.

    I tried using SDL_DisplayFormat, but it made all the transparent parts in my png sprites white, so I removed it. I know that you can create transparency in the code by making a specific color transparent, but I haven't done that. Is it worth doing, or is there another way?

    I'm not entirely sure about all the programming terms, but I think that I am double-buffering. I'll post some of the code if you want to look at it yourself. Starting with the loop for the game itself (it's not really finished yet as you can see)

    Code:
        while(!quit())
        {
            blitMap();
            charMove();
            charShow();
    
    
            SDL_Flip( screen );
            SDL_Delay(1000/FPS);
        }
    
    bool quit()
    {
        if(SDL_PollEvent( &event ))
            {
                if(event.type == SDL_QUIT)
                {
                    return true;
                }
            }
        return false;
    }
    
    void blitMap()
    {
        for( int a = 0; a < (SCREEN_HEIGHT/16); a++)
        {
        for( int b = 0; b < (SCREEN_WIDTH/16); b++)
        {
            offset.x = (b)*16;
            offset.y = (a)*16;
            SDL_BlitSurface( tiles, &clip[ map[a][b] ], screen, &offset );
        }
        }
    }
    
    void charMove()
    {
        checkCharDirection();
    
    
        if( charDirection == 1 ) charPosition.y -= speed;
        else if( charDirection == 0 ) charPosition.y += speed;
        else if( charDirection == 3 ) charPosition.x -= speed;
        else if( charDirection == 2 ) charPosition.x += speed;
    
    
        if( collision( charPosition.x, charPosition.y ) )
        {
        if( charDirection == 1 ) charPosition.y += speed;
        else if( charDirection == 0 ) charPosition.y -= speed;
        else if( charDirection == 3 ) charPosition.x += speed;
        else if( charDirection == 2 ) charPosition.x -= speed;
        }
    }
    
    void checkCharDirection()
    {
        keystate = SDL_GetKeyState(NULL);
    
    
            if( keystate[SDLK_w] || keystate[SDLK_UP] ) charDirection = 1;
    
    
            else if( keystate[SDLK_s]  || keystate[SDLK_DOWN] ) charDirection = 0;
    
    
            else if( keystate[SDLK_a] || keystate[SDLK_LEFT] ) charDirection = 3;
    
    
            else if( keystate[SDLK_d] || keystate[SDLK_RIGHT] ) charDirection = 2;
    }
    
    bool collision(int x, int y)
    {
        
        int xTile = x/16;
        int yTile = y/16;
        int xTileEnd = ( x+16 )/16;
        int yTileEnd = ( y+16 )/16;
        
        if( walkable[yTile][xTile] == false ) return true;
        else if( walkable[yTile][xTileEnd] == false ) return true;
        else if( walkable[yTileEnd][xTile] == false ) return true;
        else if( walkable[yTileEnd][xTileEnd] == false ) return true;
        else return false;
    }
    
    void charShow()
    {
        charAnimation();
        SDL_BlitSurface( character, &clipChar[(charDirection*3)+status], screen, &charPosition );
    }
    
    void charAnimation()
    {
        timer++;
        if( timer == ANIMATION_DELAY )
        {
            timer = 0;
            if(status < 2) status = 2;
            else if(status == 2) status = 1;
        }
    }

  7. #7
    Registered User
    Join Date
    Oct 2011
    Posts
    9
    Thanks for the help everyone! Using SDL_DisplayFormatAlpha( loadedImage ) when I load the images solved the problem.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sdl blitting
    By lilhawk2892 in forum Game Programming
    Replies: 4
    Last Post: 09-16-2006, 03:49 PM
  2. Transparent Blitting
    By PsychoBrat in forum Windows Programming
    Replies: 2
    Last Post: 01-15-2003, 12:35 AM
  3. map blitting problem
    By Flikm in forum Game Programming
    Replies: 2
    Last Post: 04-17-2002, 03:32 PM
  4. blitting
    By muttski in forum Game Programming
    Replies: 3
    Last Post: 04-05-2002, 04:31 PM
  5. blitting problem
    By cozman in forum Game Programming
    Replies: 5
    Last Post: 04-01-2002, 10:01 PM