2

I am trying to get a knight on a horse (inauspiciously named "guy") to run across the screen. The knight currently exists in my directory as 2 .png files, to simulate some poorly animated galloping. I was able to get him to appear when he was a .bmp, but I would like to utilize the transparency of png files - I've also tried and failed with opening tif files. How can I alter my code in order to get him to appear from a .png loaded into SDL correctly?

Here is my .cpp file:

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

using namespace std;

int source_sdl( int argc, char* args[] ) {

int switch = 1;
int running = 1;

// surface & rect declarations
SDL_Surface* ground = NULL;
SDL_Surface* guy = NULL;
SDL_Surface* guy2 = NULL;
SDL_Rect guylocationRect;
SDL_Rect groundlocationRect;

// initialize SDL & the screen
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 875, 625, 32, SDL_SWSURFACE );

// open .png files
SDL_RWops* guy_rwop;
SDL_RWops* guy2_rwop;
guy_rwop = SDL_RWFromFile("tiffKnight.png", "rb");
guy2_rwop = SDL_RWFromFile("tiffKnight2.png", "rb");
guy = IMG_LoadPNG_RW(guy_rwop);
guy2 = IMG_LoadPNG_RW(guy2_rwop);
guylocationRect.x = 300;
guylocationRect.y = 300;
groundlocationRect.x = 300;
groundlocationRect.y = 300;

SDL_Event occur;

// animation loop (currently endless)
while (running == 1){

    SDL_Flip( screen );
    SDL_Delay( 300 );

    if (gallop > 89) gallop=0;

    // draw the ground
    for( int yu = 0; yu<35; yu++){
         groundlocationRect.x=25*yu;
         groundlocationRect.y=5*25;
         SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
    }
    // draw the gallopping
    guylocationRect.x=10*gallop;
    guylocationRect.y=5*25;
    if( switch ){
        SDL_BlitSurface( guy, NULL, screen, &guylocationRect );
    }else{
        SDL_BlitSurface( guy2, NULL, screen, &guylocationRect );
    }
    gallop++;
    switch = (switch+1)%2;
    for(int u = 6; u < 25; u++){
        for(int yu = 0; yu < 35; yu++){ 
            groundlocationRect.x = 25*yu;
            groundlocationRect.y = 25*u;
            SDL_BlitSurface( ground, NULL, screen, &groundlocationRect );
        }
    }
}
SDL_FreeSurface( guy );
SDL_FreeSurface( guy2 );
SDL_FreeSurface( ground );
}

As I currently have it, the knight does not appear and I receive no errors (a consequence of the SDL screen being open?) Fail checks such as

if(!guy) {
    cout << "IMG_LoadPNG_RW: %s\n" << IMG_GetError();
}

Have also yielded no results. my .h file is simply:

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

using namespace std;
 int source_sdl( int argc, char* args[] );

And my main.cpp:

#include "SDL/SDL.h"
#include <iostream>
#include "source_sdl.h"
using namespace std;

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

    source_sdl( argc, args );

}
genpfault
  • 51,148
  • 11
  • 85
  • 139
  • since guy is != null you could try to see if the loaded surface looks as expected: printf("Surface %s: w:%d h:%d bpp:%d\n", "guy", guy->w, guy->h, guy->format->BitsPerPixel); – D-rk Mar 28 '14 at 08:12
  • Maybe check the SDL_BlitSurface return codes? – nemasu Mar 28 '14 at 08:50
  • Just out of curiosity: Why use SDL when you are coding in C++? Wouldn't SFML be a better choice then? Since SDL is based on C and SFML on C++. – Skalli Mar 28 '14 at 08:58
  • Why you're using surfaces? Textures are faster. And you can easily load .png into texture using `IMG_LoadTexture()`. – HolyBlackCat Jun 07 '14 at 17:18
  • Possible duplicate of [Blitting a transparent .PNG image onto a screen](http://stackoverflow.com/questions/4425901/blitting-a-transparent-png-image-onto-a-screen) | http://stackoverflow.com/questions/4153055/how-to-load-jpg-png-textures-in-an-sdl-opengl-app-under-osx – Ciro Santilli OurBigBook.com Jan 20 '17 at 22:57

1 Answers1

1

If you really want to stick with SDL in C++, I suggest you to use the SDL_image library and use a function like :

SDL_Surface * loadImage(std::string const & filename)
{
    SDL_Surface * img = nullptr;
    SDL_Surface * tmp = IMG_Load(filename.c_str());

    if (tmp)
    {
        img = SDL_DisplayFormatAlpha(tmp);
        SDL_FreeSurface(tmp);
    }
    return img;
}

An example of a more modern and safe approach would looke like this:

using SurfacePtr = std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)>;

SurfacePtr loadImage(std::string const & filename)
{
    SurfacePtr img { nullptr,                    &SDL_FreeSurface };
    SurfacePtr tmp { IMG_Load(filename.c_str()), &SDL_FreeSurface };

    if (tmp)
        img.reset(SDL_DisplayFormatAlpha(tmp.get()));

    return img;
}

Or better, use an existing C++ Binding like libSDL2pp (I have nothing to do with them).

Chnossos
  • 9,971
  • 4
  • 28
  • 40
  • I'm having trouble wrapping my head around some of the syntax in the modern approach, and maybe it's just because MSVC++ 2012 won't compile it... Is there an alternate (clearer/more traditional maybe?) syntax for `surface_ptr img { nullptr, SDL_FreeSurface };`? – Justin ᚅᚔᚈᚄᚒᚔ Jan 01 '15 at 21:59
  • Sure, use `surface_ptr img(nullptr, SDL_FreeSurface);` instead. – Chnossos Jan 02 '15 at 00:47
  • You can wrap the deleter in `std::integral_constant`, then it doesn't occupy any memory. Not sure if there's any practical benefit though. – HolyBlackCat May 18 '22 at 12:54