Sign in to follow this  
karaman

SDL_CreateRGBSurface and SDL_BlitSurface

Recommended Posts

I'm writing a little game engine andf have a tileLoad function. This gets a bmp file and cuts it into 32*32 sprites and blits it to
SDL_Surface *Sprites [3][30]
. But, my code doesn't work, I can have maybe little 1 bit errors in the FOR algoritma but I also without the FOR loop, just with
SDL_BlitSurface(bmp, &rect, Sprites[0][0], 0);
it doesn't work (the program stops). Here is the functions, hte input (bmp file is correct: Sprites[0][0]=bmp works).
void cGraphics::loadTile(string filename, string name)
{
    SDL_Surface* bmp = SDL_LoadBMP(filename.c_str());

    SDL_Rect rect;
    rect.x=0;
    rect.y=0;
    for(int w=0; w<bmp->w; w+=SPRITE_WIDTH)
    {
        for(int h=0; h<bmp->h; h+=SPRITE_HEIGHT)
        {
            Sprites[nextTile][nextSprite] =
            SDL_CreateRGBSurface(SDL_SWSURFACE, SPRITE_WIDTH, SPRITE_HEIGHT, 1, r_mask, g_mask, b_mask, a_mask);

            //SDL_SetClipRect(bmp, &rect);

            //Sprites[nextTile][nextSprite][0] =
            SDL_BlitSurface(bmp, &rect, Sprites[nextTile][nextSprite], 0);
            //SDL_BlitSurface(Sprites[nextTile][nextSprite], 0, bmp, &rect);
            spriteLevels[nextTile]=0;//For,later

            nextSprite++;
            if(!nextSprite<SPRITES)
                h=bmp->h;
        }
    }
    sprites[nextTile]=nextSprite-1;
    nextSprite=0;
    nextTile++;
    //SDL_BlitSurface(bmp, &rect, Sprites[0][0], 0);
}
Thanks.

Share this post


Link to post
Share on other sites
I believe that rect you're using should hold the x and y coords and size of the tile you're blitting whenever you're blitting from bmp.

So, something like...

void cGraphics::loadTile(string filename, string name)
{
SDL_Surface* bmp = SDL_LoadBMP(filename.c_str());

SDL_Rect rect;
rect.w=SPRITE_WIDTH;
rect.h=SPRITE_HEIGHT;

for(rect.y=0; rect.y<bmp->h; rect.y+=SPRITE_HEIGHT)
{
nextSprite=0;
for(rect.x=0; rect.x<bmp->w; rect.x+=SPRITE_WIDTH)
{
Sprites[nextTile][nextSprite] =
SDL_CreateRGBSurface(SDL_SWSURFACE, SPRITE_WIDTH, SPRITE_HEIGHT, 1, r_mask, g_mask, b_mask, a_mask);

SDL_BlitSurface(bmp, &rect, Sprites[nextTile][nextSprite], 0);
[...]


Also, it doesn't seem quite right to me that

nextSprite=0;
nextTile++;

is outside the for-loops. tho that could well be for some sound reason I'm unaware of... and I can't see what good sprites[nextTile]=nextSprite-1; does...

Share this post


Link to post
Share on other sites
Thanks for your reply.

sprites[nextTile]=nextSprite-1;
int sprites holds the lenght of the SDL_Surface* Sprites[][]

nextSprite=0;
Reset the position for later loadTile calls.

nextTile++;
Iterates so that in the future a new tile will be loaded to Sprites[1][nextSprite]

Now, I just wrote a simple code that must blit the image to a 32*32 pixel, but I get a black screen:

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
static const Uint32 rmask = 0xFF000000;
static const Uint32 gmask = 0x00FF0000;
static const Uint32 bmask = 0x0000FF00;
static const Uint32 amask = 0x000000FF;
#else
static const Uint32 rmask = 0x000000FF;
static const Uint32 gmask = 0x0000FF00;
static const Uint32 bmask = 0x00FF0000;
static const Uint32 amask = 0xFF000000;
#endif

SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");

SDL_Rect rect;
rect.w=32;
rect.h=32;

SDL_Surface* Sprites[0][0] =
SDL_CreateRGBSurfaceFrom(bmp, 32, 32, screen->format->BitsPerPixel, 0, rmask, gmask, bmask, amask);
SDL_BlitSurface(bmp, &rect, Sprites[0][0], 0);


And here is the source file (with codeblocks project file and image:
http://www.keepmyfile.com/download/e2f5331268962

Thanks very much.

Share this post


Link to post
Share on other sites
Quote:
sprites[nextTile]=nextSprite-1;
int sprites holds the lenght of the SDL_Surface* Sprites[][]

nextSprite=0;
Reset the position for later loadTile calls.

nextTile++;
Iterates so that in the future a new tile will be loaded to Sprites[1][nextSprite]

Aha. Figured there might have been some reason like that for the nextTile++ bit, while I missed the difference in capitalization on the Sprites/sprites thing :)

So anyways. Not awfully familiar with SDL_CreateRBGSurfaceFrom (after reading documentation on it, it doesn't seem awfully suited for this thing, unless I'm missing something), but messed some with the code. Not too sure about what details are wrong in each thing I changed, but got it to work by using SDL_CreateRBGSurface, without using the mask variables, and setting rect.x/y to 0 before blitting from bmp to Sprite[0][0]. (also, since not using SDL_CreateRBGSurfaceFrom, freeing the bmp surface once the tile(s) are blitted to the Sprites-surfaces, instead of at the end of after the loop).

So:

SDL_Surface* Sprites[0][0];
SDL_Surface* bmp = SDL_LoadBMP("cb.bmp");
SDL_Rect rect;
rect.x=0;
rect.y=0;
rect.w=32;
rect.h=32;
Sprites[0][0] = SDL_CreateRGBSurface(<SDL_SWSURFACE or SDL_HWSURFACE or whatever>, 32, 32, screen->format->BitsPerPixel, 0, 0, 0, 0);
SDL_BlitSurface(bmp, &rect, Sprites[0][0], 0);
SDL_FreeSurface(bmp); bmp = NULL;


Also, at line 90 in source, I changed it from SDL_BlitSurface(Sprites[0][2], 0, screen, 0); to SDL_BlitSurface(Sprites[0][0], 0, screen, 0);

Share this post


Link to post
Share on other sites
Perhaps an alternative solution?

You don't need to cut the tiles into seperate surfaces, you can control the amount of tile drawn using the SDL_Rects sent to SDL_BlitSurface();

Then you'll only need 1 surface, the surface with all the tiles on it.

Here is some sample code that works on a 3x3 32*32 pixel bitmap.
You should be able to adapt it to your sprite sheet layout should you choose to use this method.

#include "SDL.h"
#include <iostream>
#include <string>

const int SPRITE_WIDTH = 32, SPRITE_HEIGHT = 32;


SDL_Surface *tiles = NULL;

void draw( int index )
{
SDL_Surface * screen = SDL_GetVideoSurface();
SDL_FillRect(screen,NULL,0);

int numTilesAcross = tiles->w / SPRITE_WIDTH;
int numTilesDown = tiles->h / SPRITE_HEIGHT;
SDL_Rect source = { index % numTilesAcross * SPRITE_WIDTH, index / numTilesDown * SPRITE_HEIGHT,SPRITE_WIDTH,SPRITE_HEIGHT };

SDL_Rect dest = {screen->w/2,screen->h/2,0,0};
SDL_BlitSurface( tiles, &source, screen, &dest );

SDL_Flip(screen);
SDL_Delay(10);
}

int main( int , char ** )
{
SDL_Init( SDL_INIT_VIDEO );

SDL_SetVideoMode(800,600,0,SDL_ANYFORMAT);
tiles = SDL_LoadBMP("tiles.bmp");

if( tiles == NULL ){ std::cout<< SDL_GetError() << std::endl; assert(false);}
int i = 0;
bool running = true;
while(running)
{
SDL_Event e;
while(SDL_PollEvent(&e) )
{
if( e.type == SDL_QUIT )
{
running = false;
}

}
++i;
if( i == 9 ) i = 0;
draw(i);
SDL_Delay(500);
}
SDL_Quit();
return 0;
}


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