Here is a minimal SDL-1.2 text output example (stripped from the lazyfoo tutorial for ttf):
#include <SDL.h>
#include <SDL_ttf.h>
#include <string>
SDL_Surface *message = NULL;
SDL_Surface *screen = NULL;
SDL_Event event;
TTF_Font *font = NULL;
SDL_Color color = { 255, 255, 255 };
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_EVERYTHING );
screen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
TTF_Init();
SDL_WM_SetCaption( "Test message", NULL );
font = TTF_OpenFont( "anyttffont.ttf", 20 );
message = TTF_RenderText_Solid(
font, "My test message", color );
SDL_Rect offset;
offset.x = 0;
offset.y = 150;
SDL_BlitSurface( message, NULL, screen, &offset );
SDL_Flip( screen );
bool quit = false;
while( quit == false )
while( SDL_PollEvent( &event ) )
if( event.type == SDL_QUIT )
quit = true;
SDL_FreeSurface( message );
TTF_CloseFont( font );
TTF_Quit();
SDL_Quit();
return 0;
}
The resulting executable redraws the window automatically after re-exposing it (after minimizing or obscuring).
Is it possible to do something like this in SDL-2?
I tried the equivalent tutorial from lazyfoo for SDL-2, but this has code to constantly re-render the text in the event loop. It stops re-drawing when the render code is moved in front of the loop. I also tried rewriting it using the window surface directly and then using SDL_UpdateWindowSurface(gWindow);, but this behaves the same way.
After view this guide http://lazyfoo.net/tutorials/SDL/05_optimized_surface_loading_and_soft_stretching/index.php i want to use SDL_BlitScaled to scale a surface and then use SDL_CreateTextureFromSurface to create a texture for the surface. Here is the load_media code that is causing the core dump. Can you help me on why it is causing this? I think its the line ConvertSurface that is causing the issue.
bool Texture::load_from_file( std::string path ) {
//deallocate preexisiting texture
free();
//final texture
SDL_Texture* new_texture = NULL;
SDL_Surface* optimizedSurface = NULL;
//load image at path
SDL_Surface* loaded_surface = SDL_LoadBMP( path.c_str() );
temp = loaded_surface;
window_surface = SDL_GetWindowSurface( g_window );
if ( loaded_surface == NULL ) {
printf("Unable to load image %s. SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else {
//set key image
//SDL_SetColorKey ( loaded_surface, SDL_TRUE, SDL_MapRGB( window_surface->format, 0, 0xFF, 0xFF ) );
optimizedSurface = SDL_ConvertSurface( loaded_surface, window_surface->format, NULL );
SDL_Rect stretchRect;
stretchRect.x = 0;
stretchRect.y = 0;
stretchRect.w = SCREEN_WIDTH;
stretchRect.h = SCREEN_HEIGHT;
SDL_BlitScaled( optimizedSurface, NULL, window_surface, &stretchRect );
//create texture from pixels
new_texture = SDL_CreateTextureFromSurface( g_renderer, window_surface );
if ( new_texture == NULL ) {
printf("Unable to create texture from %s. SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
else {
//get dimensions
m_width = window_surface->w;
m_height = window_surface->h;
}
//deallocate old SDL_Surface
SDL_FreeSurface( loaded_surface );
}
m_texture = new_texture;
return m_texture != NULL;
}
I have just gotten too frustrated with trying to figure this out. I have been following http://lazyfoo.net/tutorials/SDL/index.php. I then tried to start making a game with SDL2 but ran into this error very quickly: I can't render anything to the screen. The screen pops up, and I can clear it correctly and everything. If I call SDL_GetError(), the output is "Invalid Renderer". I've checked the code to try to find out where this error could be caused, and searched the internet to no avail. Something that might be causing the problem is that I have a class which has a render method. This render method calls a render method on its texture. That might be the place where I screwed up somehow, but I can't tell.
Source code:
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <string>
#include <stdio.h>
const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT= 960;
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
enum MOVEMENT_STATES
{
DOWN1,
DOWN2,
LEFT1,
LEFT2,
RIGHT1,
RIGHT2,
UP1,
UP2,
MOVEMENT_STATES_TOTAL
};
//Texture wrapper class
class LTexture
{
public:
//Initializes variables
LTexture(std::string path);
//Deallocates memory
~LTexture();
#ifdef _SDL_TTF_H
//Creates image from font string
bool loadFromRenderedText( std::string textureText, SDL_Color textColor );
#endif
//Deallocates texture
void free();
//Set color modulation
void setColor( Uint8 red, Uint8 green, Uint8 blue );
//Set blending
void setBlendMode( SDL_BlendMode blending );
//Set alpha modulation
void setAlpha( Uint8 alpha );
//Renders texture at given point
void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );
//Gets image dimensions
int getWidth();
int getHeight();
private:
//Loads image at specified path
bool loadFromFile( std::string path );
//The actual hardware texture
SDL_Texture* mTexture;
//Image dimensions
int mWidth;
int mHeight;
};
//Sprite classes
class Entity
{
public:
Entity(int hp);
~Entity();
//void handleEntity(); Unimplemented
void render(int x, int y);
int health;
int maxHealth;
LTexture* mCurrentTexture;
};
Entity::Entity(int hp)
{
mCurrentTexture = NULL;
health = hp;
maxHealth = hp;
}
Entity::~Entity()
{
mCurrentTexture = NULL;
}
void Entity::render(int x, int y)
{
//If current texture is non-null, render it
if (mCurrentTexture != NULL)
{
(*mCurrentTexture).render(x, y);
}
else
{
printf("Texture is null!\n");
}
}
LTexture::LTexture(std::string path)
{
//Initialize
mTexture = NULL;
loadFromFile(path);
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture()
{
//Deallocate
free();
}
bool LTexture::loadFromFile( std::string path )
{
//Get rid of preexisting texture
free();
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
//Color key image
SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
if( newTexture == NULL )
{
printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
else
{
//Get image dimensions
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
//Return success
mTexture = newTexture;
return mTexture != NULL;
}
#ifdef _SDL_TTF_H
bool LTexture::loadFromRenderedText( std::string textureText, SDL_Color textColor )
{
//Get rid of preexisting texture
free();
//Render text surface
SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
if( textSurface != NULL )
{
//Create texture from surface pixels
mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
if( mTexture == NULL )
{
printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
}
else
{
//Get image dimensions
mWidth = textSurface->w;
mHeight = textSurface->h;
}
//Get rid of old surface
SDL_FreeSurface( textSurface );
}
else
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
//Return success
return mTexture != NULL;
}
#endif
void LTexture::free()
{
//Free texture if it exists
if( mTexture != NULL )
{
SDL_DestroyTexture( mTexture );
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::setColor( Uint8 red, Uint8 green, Uint8 blue )
{
//Modulate texture rgb
SDL_SetTextureColorMod( mTexture, red, green, blue );
}
void LTexture::setBlendMode( SDL_BlendMode blending )
{
//Set blending function
SDL_SetTextureBlendMode( mTexture, blending );
}
void LTexture::setAlpha( Uint8 alpha )
{
//Modulate texture alpha
SDL_SetTextureAlphaMod( mTexture, alpha );
}
void LTexture::render( int x, int y, SDL_Rect* clip, double angle, SDL_Point* center, SDL_RendererFlip flip )
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
}
int LTexture::getWidth()
{
return mWidth;
}
int LTexture::getHeight()
{
return mHeight;
}
bool init()
{
bool success = true;
//Initialize SDL
if(SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Enable VSync
if(!SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"))
{
printf("Warning: VSync not enabled!");
}
//Set texture filtering to linear
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
printf( "Warning: Linear texture filtering not enabled!" );
}
}
//Create window
gWindow = SDL_CreateWindow("Dungeon Dash", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("SDL could not create window! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create renderer for window
gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
if (gRenderer == NULL)
{
printf("SDL could not create renderer! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if( !( IMG_Init( imgFlags ) & imgFlags ) )
{
printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
}
}
return success;
}
int main(int argc, char* args[])
{
if(!init())
{
printf("SDL could not initialize!\n");
}
else
{
bool quit = false;
SDL_Event e; //Event handler
//Load all textures
LTexture boltTexture("graphics/bolt.png");
LTexture burst1Texture("graphics/burst1.png");
LTexture burst2Texture("graphics/burst2.png");
LTexture chestTexture("graphics/chest.png");
LTexture coinTexture("graphics/coin.png");
LTexture emptyTileTexture("graphics/emptyTile.png");
LTexture floorTileTexture("graphics/floorTile.png");
LTexture healthPadTexture("graphics/healthPad.png");
LTexture keyTexture("graphics/key.png");
LTexture snakeDown1Texture("graphics/snakeDown1.png");
LTexture snakeDown2Texture("graphics/snakeDown2.png");
LTexture snakeLeft1Texture("graphics/snakeLeft1.png");
LTexture snakeLeft2Texture("graphics/snakeLeft2.png");
LTexture snakeRight1Texture("graphics/snakeRight1.png");
LTexture snakeRight2Texture("graphics/snakeRight2.png");
LTexture snakeUp1Texture("graphics/snakeUp1.png");
LTexture snakeUp2Texture("graphics/snakeUp2.png");
LTexture spiderDown1Texture("graphics/spiderDown1.png");
LTexture spiderDown2Texture("graphics/spiderDown2.png");
LTexture spiderLeft1Texture("graphics/spiderLeft1.png");
LTexture spiderLeft2Texture("graphics/spiderLeft2.png");
LTexture spiderRight1Texture("graphics/spiderRight1.png");
LTexture spiderRight2Texture("graphics/spiderRight2.png");
LTexture spiderUp1Texture("graphics/spiderUp1.png");
LTexture spiderUp2Texture("graphics/spiderUp2.png");
LTexture teleportPadTexture("graphics/teleportPad.png");
LTexture upgradePadTexture("graphics/upgradePad.png");
LTexture wallTileDownTexture("graphics/wallTileDown.png");
LTexture wallTileLeftTexture("graphics/wallTileLeft.png");
LTexture wallTileRightTexture("graphics/wallTileRight.png");
LTexture wallTileUpTexture("graphics/wallTileUp.png");
LTexture wizardDown1Texture("graphics/wizardDown1.png");
LTexture wizardDown2Texture("graphics/wizardDown2.png");
LTexture wizardLeft1Texture("graphics/wizardLeft1.png");
LTexture wizardLeft2Texture("graphics/wizardLeft2.png");
LTexture wizardRight1Texture("graphics/wizardRight1.png");
LTexture wizardRight2Texture("graphics/wizardRight2.png");
LTexture wizardUp1Texture("graphics/wizardUp1.png");
LTexture wizardUp2Texture("graphics/wizardUp2.png");
//Main player
Entity player1(20);
player1.mCurrentTexture = &wizardDown1Texture;
//Main loop
while(!quit)
{
//Event loop
while(SDL_PollEvent(&e) != 0)
{
if(e.type == SDL_QUIT)
{
quit = true;
}
}
//Clear screen
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
SDL_RenderClear(gRenderer);
player1.render(0, 0);
//Update screen
SDL_RenderPresent(gRenderer);
}
//If script reaches here, user has exited; quit program
//Free loaded images
boltTexture.free();
burst1Texture.free();
burst2Texture.free();
chestTexture.free();
coinTexture.free();
emptyTileTexture.free();
floorTileTexture.free();
healthPadTexture.free();
keyTexture.free();
snakeDown1Texture.free();
snakeDown2Texture.free();
snakeLeft1Texture.free();
snakeLeft2Texture.free();
snakeRight1Texture.free();
snakeRight2Texture.free();
snakeUp1Texture.free();
snakeUp2Texture.free();
spiderDown1Texture.free();
spiderDown2Texture.free();
spiderLeft1Texture.free();
spiderLeft2Texture.free();
spiderRight1Texture.free();
spiderRight2Texture.free();
spiderUp1Texture.free();
spiderUp2Texture.free();
teleportPadTexture.free();
upgradePadTexture.free();
wallTileDownTexture.free();
wallTileLeftTexture.free();
wallTileRightTexture.free();
wallTileUpTexture.free();
wizardDown1Texture.free();
wizardDown2Texture.free();
wizardLeft1Texture.free();
wizardLeft2Texture.free();
wizardRight1Texture.free();
wizardRight2Texture.free();
wizardUp1Texture.free();
wizardUp2Texture.free();
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
}
Thanks in advance for any help.
I found this question because I was getting the same error from SDL_GetError. The answers here that indicate that SDL_GetError may say "Invalid Renderer" in situations where there is no error were informative. SDL_GetError can only be relied on in cases where the last SDL function called actually indicated an error.
My situation was slightly different, though. I was calling SDL_WaitEventTimeout, which returns 1 to indicate an early return due to an event, or 0 for either an expired timer or for an error, and makes the user rely on SDL_GetError to determine whether an error occurred. In this case, calling SDL_ClearError before calling SDL_WaitEventTimeout is crucial. Plus, SDL_GetError returns an empty string, not a null pointer, when there is no error.
int frameRate = 30;
SDL_Event e;
SDL_ClearError();
int ret = SDL_WaitEventTimeout( &e, 1000/frameRate );
if ( ret )
{
// event received, process events
}
else
{
// timeout or error; have to check
const char *s = SDL_GetError();
if ( *s )
{
cout << "SDL_WaitEventTimeout: " << s << endl;
}
else
{
// normal timeout, do normal actions
}
}
This appears to be a flaw in the design of SDL_WaitEventTimeout, which is wasting most of the space in its return value. It really should be returning -1 when it causes an error, 0 when it times out, and the number of milliseconds remaining when an event occurs. I suspect it's actually deprecated as a frame timer, and I'll have to rely on SDL_PollEvent for events and have to use OS/hardware-native timers for frame sync, which wastes the portability of SDL.
The line which throws the error is the one creating the renderer, but that error can be ignored (as it does not return NULL). SDL uses a macro to check if the renderer is OK and it automatically sets that error string if its not ok. It might be doing that check too early. This has nothing to do with your problem, though.
Your problem here is because in LTexture constructor you call loadFromFile(), which sets mWidth and mHeight properly. Afterwards you set them to 0 again, making your renderQuad have no area, thus making your texture not to render.
Set them to 0 before that or, even better, set them to 0 in the initializer list:
LTexture::LTexture(std::string path)
: mTexture(NULL), mWidth(0), mHeight(0)
{
loadFromFile(path);
}
Also, LTexture class has a method called free, which, albeit not a reserved name, may cause confusion in your fellow colleagues (as it did with me :), you may consider a different name.
Try changing the flags that you pass to SDL_CreateRenderer(). I was having the same issue as you, and I eventually discovered that it was that, on my machine, SDL has trouble with hardware-accelerated rendering (which happens to be the default). Try changing that SDL_RENDERER_ACCELERATED to a SDL_RENDERER_SOFTWARE, and see if that helps.
Additionally, whenever you have a particularly tricky bug that you are trying to fix, break the problem down. You have a huge (for Stack Overflow) amount of code here, and had you cut it down to just the rendering bits then (1) others might have been able to help you more quickly and (2) you may have been able to solve the problem by yourself.
Situation: I currently am trying to render a few things (images and some text) using SDL_image and SDL in C++. However I am coming across some problems which look to be like buffering issues however with my attempts to fix this, Ive been stuck for hours with no avail.
Problem: When rendering, the screen gives a Single-buffering like effect where the image in its previous position is still being displayed on screen like it would in the last buffer. I suspect the problem lies somewhere within my draw function (main loop function)
Here is my main.cpp:
#include "SDL.h"
#include "SDL_image.h"
#include "Player.h"
#include "Values.h"
#include <string>
#include <sstream>
#include "SDL_ttf.h"
#include "Timer.h"
//The surfaces that will be used
SDL_Surface *message = NULL;
SDL_Surface *background = NULL;
SDL_Surface *text = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *startStop = NULL;
SDL_Surface *pauseMessage = NULL;
SDL_Surface *seconds = NULL;
//The font thats going to be used
TTF_Font *font = NULL;
//The colour of the font
SDL_Color textColor = {255,255,255};
Player ** player;
Timer myTimer;
bool quit = false;
Uint32 start = 0;
bool running = true;
int fame = 0;
bool cap = true;
//Timer fps;
SDL_Event event;
void clean_up()
{
//Free the surfaces
//SDL_FreeSurface( message );
player[0]->clean();
SDL_FreeSurface( background );
SDL_FreeSurface( seconds );
SDL_FreeSurface(startStop);
SDL_FreeSurface(pauseMessage);
TTF_CloseFont(font);
TTF_Quit();
//Quit SDL
SDL_Quit();
}
SDL_Surface *load_image( std::string filename )
{
//Temporary storage for the image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized image that will be used
SDL_Surface* optimizedImage = NULL;
//Load the image
loadedImage = SDL_LoadBMP( filename.c_str() );
//If nothing went wrong in loading the image
if( loadedImage != NULL )
{
//Create an optimized image
optimizedImage = SDL_DisplayFormat( loadedImage );
//Free the old image
SDL_FreeSurface( loadedImage );
}
//Return the optimized image
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
//Make a temporary rectangle to hold the offsets
SDL_Rect offset;
//Give the offsets to the rectangle
offset.x = x;
offset.y = y;
//Blit the surface
SDL_BlitSurface( source, NULL, destination, &offset );
}
bool loadFiles()
{
player[0]->load_files();
background = load_image( "Floor1.bmp" );
//Open the font
font = TTF_OpenFont("lazy.ttf",28);
//If there was a problem in loadin the font
if(font == NULL)
{
return false;
}
return true;
}
bool init()
{
//Initialize all SDL subsystems
SDL_Init( SDL_INIT_EVERYTHING );
//Set up the screen
//screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 0,
SDL_HWSURFACE | SDL_DOUBLEBUF );
//Initialize SDL_tff
if(TTF_Init() == -1)
{
return false;
}
//Set the window caption
SDL_WM_SetCaption( "10 seconds", NULL );
player = new Player*[1];
player[0] = new Player(screen);
loadFiles();
return true;
};
void mainloop()
{
startStop = TTF_RenderText_Solid(font, "Press S to start or stop the timer", textColor);
pauseMessage = TTF_RenderText_Solid(font, "Press P to pause or unpause the timer", textColor);
myTimer.start();
while (quit == false)
{
//While there's events to handle
while( SDL_PollEvent( &event ) )
{
//Handle events for the dot
player[0]->handleInput(event);
if (event.type == SDL_KEYDOWN)
{
//if s was pressed
if(event.key.keysym.sym == SDLK_s)
{
//if the timer is running
if(myTimer.isStarted() == true)
{
//Stop the timer
myTimer.stop();
}
else
{
//Start the timer
myTimer.start();
}
}
if (event.key.keysym.sym == SDLK_p)
{
//If the timer is paused
if (myTimer.isPaused() == true)
{
//Unpause the timer
myTimer.unpause();
}
else
{
//Pause the timer
myTimer.pause();
}
}
}
//If the user has Xed out the window
else if( event.type == SDL_QUIT )
{
//Quit the program
quit = true;
}
}
//Apply all images to screen
apply_surface( 0, 0, background, screen );
apply_surface( ( SCREEN_WIDTH - startStop->w ) / 2, 200, startStop, screen );
apply_surface( ( SCREEN_WIDTH - pauseMessage->w ) / 2, 250, pauseMessage, screen );
//The timers time as a string
std::stringstream time;
//convert the timers time to a string
time << "Timer: " << myTimer.getTicks() / 1000.f;
seconds = TTF_RenderText_Solid( font, time.str().c_str(), textColor );
//Render the time surface
apply_surface( ( SCREEN_WIDTH - seconds->w ) / 2, 0, seconds, screen );
/Free the time surface
//PlayerHandling
player[0]->move();
player[0]->setCamera();
player[0]->draw();
SDL_FreeSurface( seconds );
SDL_Flip(screen);
}
}
int main( int argc, char* args[] )
{
init();
mainloop();
clean_up();
return 0;
}
It seems, judging by the graphical effect and the fact that your background is all black, your code fails in loading the background. You can test it by just filling background with a color.
background = SDL_CreateRGBSurface( 0, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 );
SDL_FillRect( background, NULL, SDL_MapRGBA( background->format, 125, 125, 0, 255) );
Since SDL does not break or warn you if you try using a SDL_Surface* that points to NULL, I also suggest adding an error message to your load_image :
SDL_Surface *load_image( std::string filename )
{
//Temporary storage for the image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized image that will be used
SDL_Surface* optimizedImage = NULL;
//Load the image
loadedImage = SDL_LoadBMP( filename.c_str() );
//If nothing went wrong in loading the image
if( loadedImage != NULL )
{
//Create an optimized image
optimizedImage = SDL_DisplayFormat( loadedImage );
//Free the old image
SDL_FreeSurface( loadedImage );
} else
{
std::cout << "ERROR : Failed to load image : " << filename << std::endl;
}
//Return the optimized image
return optimizedImage;
}
I'm getting a segmentation fault from SDL_BlitSurface in C++.
here's the code
mainScreen->draw( 0, 0, background, NULL );
(where mainScreen is an instance of the Screen class) and the draw function of the Screen class is implemented as
void Screen::draw( float x, float y, Texture* source, SDL_Rect* clip)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
if ( source->myimage == NULL ) throw 5;
if ( this->screen == NULL ) throw 6;
SDL_BlitSurface( source->myimage, NULL, this->screen, &offset );
}
and Texture is defined as follows:
class Texture
{
public:
Texture(std::string imagepath);
~Texture();
private:
SDL_Surface* myimage;
float width;
float height;
friend class Screen;
//friend void Screen::draw( float x, float y, Texture source, SDL_Rect* clip);
};
and implemented
#include "Texture.h"
Texture::Texture(std::string filepath)
{
// Initialize the image to NULL to avoid any pointer issues
myimage = NULL;
// OPTIMIZED FOR PNGs
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = IMG_Load( filepath.c_str() );
if ( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormatAlpha( loadedImage ); // Notice no colour keying (use transparent PNGs)
}
myimage = optimizedImage;
SDL_FreeSurface( loadedImage );
SDL_FreeSurface( optimizedImage );
if (myimage == NULL)
{
// Some kind of error
throw 4;
}
}
Texture::~Texture()
{
SDL_FreeSurface( myimage );
}
I've stepped through the area where the image is loaded into the Texture class and that seems to work fine.
Also, I know the this->screen is loaded correctly as I use SDL_FillRect with it in a separate function.
Don't do this:
SDL_FreeSurface( optimizedImage );
You aren't done with the surface (it gets assigned to myimage).