SDL_BlitSurface Segmentation fault - c++

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).

Related

SDL_ConvertSurface Causing core dump

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;
}

SDL 2.0 - Invalid Renderer Error

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.

SDL freeze (black screen)

Here is my full code.
When I click right for a few times(animation works normally), the screen freezes. I think the lines from if(SDL_GetTicks() - start_time < 1000) on are the problem (because of too many executions?)?
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 500;
const int SCREEN_BPP = 32;
//The surfaces
SDL_Surface *background = NULL;
SDL_Surface *upMessage = NULL;
SDL_Surface *downMessage = NULL;
SDL_Surface *leftMessage = NULL;
SDL_Surface *rightMessage = NULL;
SDL_Surface *message = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *finish = NULL;
SDL_Surface *startStop = NULL;
SDL_Surface *one = NULL;
SDL_Surface *two = NULL;
SDL_Surface *three = NULL;
SDL_Surface *four = NULL;
SDL_Surface *five = NULL;
//The event structure
SDL_Event event;
SDL_Surface *load_image( std::string filename ){
//The image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized surface that will be used
SDL_Surface* optimizedImage = NULL;
//Load the image
loadedImage = IMG_Load( filename.c_str() );
//If the image loaded
if( loadedImage != NULL )
{
//Create an optimized surface
optimizedImage = SDL_DisplayFormat( loadedImage );
//Free the old surface
SDL_FreeSurface( loadedImage );
//If the surface was optimized
if( optimizedImage != NULL )
{
//Color key surface
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF ) );
}
}
//Return the optimized surface
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
//Holds offsets
SDL_Rect offset;
//Get offsets
offset.x = x;
offset.y = y;
//Blit
SDL_BlitSurface( source, clip, destination, &offset );
}
bool init()
{
//Initialize all SDL subsystems
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return false;
}
//Set up the screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
//If there was an error in setting up the screen
if( screen == NULL )
{
return false;
}
//Set the window caption
SDL_WM_SetCaption( "Press an Arrow Key", NULL );
//If everything initialized fine
return true;
}
bool load_files()
{
//Load the background image
background = load_image( "background .png" );
message = load_image( "guy.png" );
finish = load_image( "finish .png" );
//If there was a problem in loading the background
if( background == NULL )
{
return false;
}
//If everything loaded fine
return true;
}
void clean_up()
{
//Free the surfaces
SDL_FreeSurface( background );
SDL_FreeSurface( upMessage );
SDL_FreeSurface( downMessage );
SDL_FreeSurface( leftMessage );
SDL_FreeSurface( rightMessage );
SDL_FreeSurface( startStop );
SDL_FreeSurface( one );
SDL_FreeSurface( two );
SDL_FreeSurface( three );
SDL_FreeSurface( four );
SDL_FreeSurface( five );
//Quit SDL
SDL_Quit();
}
void anim(SDL_Surface *number,std::string name[],int n){
number = NULL;
number = load_image(name[n] +".png" );
apply_surface( 0, 0, number, screen );
}
int main( int argc, char* args[] ){
bool quit = false;
bool start = true;
bool cilj_test = true;
int x=35,y=10;
bool animation = false;
Uint32 start_time = 0;
//The timer start/stop flag
bool running = false;
//Initialize
if( init() == false )
{
return 1;
}
//Load the files
if( load_files() == false )
{
return 1;
}
//Apply the background
apply_surface( 0, 0, background, screen );
//While the user hasn't quit
while( quit == false ){
//If there's an event to handle
if( SDL_PollEvent( &event ) ){
//If a key was pressed
if( event.type == SDL_KEYDOWN ){
//Set the proper message surface
switch( event.key.keysym.sym ){
case SDLK_UP:
break;
case SDLK_DOWN:
start=false;
if(y!=410 && animation==false){
y+=100;
SDL_FillRect( screen, 0, 0 );
background = NULL;
message = NULL;
background = load_image( "background .png" );
apply_surface( 0, 0, background, screen );
finish = load_image( "finish.png" );
apply_surface(506, 420, finish, screen );
message = load_image( "guy.png" );
apply_surface( x, y, message, screen );
// if()
}
break;
case SDLK_LEFT:
break;
case SDLK_RIGHT:
start=false;
if(x!=535 && animation==false){
x+=100;
SDL_FillRect( screen, 0, 0 );
background = NULL;
message = NULL;
background = load_image( "background.png" );
apply_surface( 0, 0, background, screen );
finish = load_image( "finish.png" );
apply_surface(506, 420, finish, screen );
message = load_image( "guy.png" );
apply_surface( x, y, message, screen );
if(x==535 && y==410){
start_time=SDL_GetTicks();
animation=true;
x=35,y=10;
}
}
break;
}
}
//If the user has Xed out the window
else if( event.type == SDL_QUIT )
{
//Quit the program
quit = true;
}
}
if(animation){
std::string name[5]={"one","two","three","four","five"};
if(SDL_GetTicks() - start_time < 1000){
anim(one,name,4);
} else if(SDL_GetTicks() - start_time > 1000 && SDL_GetTicks() - start_time < 2000){
anim(two,name,3);
} else if(SDL_GetTicks() - start_time > 2000 && SDL_GetTicks() - start_time < 3000){
anim(three,name,2);
} else if(SDL_GetTicks() - start_time > 3000 && SDL_GetTicks() - start_time < 4000){
anim(four,name,1);
} else if(SDL_GetTicks() - start_time > 4000 && SDL_GetTicks() - start_time < 5000){
anim(five,name,0);
} else if(SDL_GetTicks() - start_time > 5000){
SDL_FillRect( screen, 0, 0 );
background = NULL;
message = NULL;
background = load_image( "background.png" );
apply_surface( 0, 0, background, screen );
finish = load_image( "finish.png" );
apply_surface(506, 420, finish, screen );
message = load_image( "guy.png" );
apply_surface( x, y, message, screen );
animation=false;
start_time=0;
}
}
if( message != NULL ){
if(start){
apply_surface(35, 10, message, screen );
apply_surface(506, 420, finish, screen );
}
message = NULL;
}
//Update the screen
if( SDL_Flip( screen ) == -1 ){
return 1;
}
}
//Clean up
clean_up();
return 0;
}
There are two issues with your code.
You do not have a while loop, meaning that the application will draw once, get one input, and stop. You are experiencing a freeze because there are too many events on the event queue.
Not really the cause of your problem, but it would show up eventually. You are loading the image each time you want to draw it. Instead load all of the images before, and just apply the correct surface. If you won't loading the images and not freeing them will result in no running out of memory.
EDIT:
After seeing your whole code, it is the second issue that is the problem. Load all your images before the loop, and just blit them accordingly.

SDL_BlitScaled doesn't work

here is my c++ code:
#include <SDL2/SDL.h>
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_VIDEO );
gWindow = SDL_CreateWindow( "test", 0,0,640,480, SDL_WINDOW_SHOWN );
gRenderer = SDL_CreateRenderer(gWindow,-1,SDL_RENDERER_ACCELERATED);
SDL_Surface* x = SDL_CreateRGBSurface(0,50,50,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Surface* y = SDL_CreateRGBSurface(0,640,480,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Rect a = {0,0,50,50};
SDL_RenderClear(gRenderer);
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,255,0,255));
SDL_Rect dest = {0,0,100,100};
SDL_BlitScaled( x, &a, y, &dest ); //Does nothing
dest.x = 200;
SDL_BlitSurface( x, &a, y, &dest );
SDL_Texture* t;
t = SDL_CreateTextureFromSurface(gRenderer,y);
SDL_RenderCopy(gRenderer,t,NULL,NULL);
SDL_RenderPresent(gRenderer);
SDL_Delay(2000);
return 0;
}
well,when you compile this code,you will see there is ONLY ONE rect on the screen.The function SDL_BlitScaled does nothing.
I'm working with Archlinux,gcc 4.8.2,SDL 2.0.1
According to Retired Ninja's answer,I changed my code:
#include <SDL2/SDL.h>
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
int main( int argc, char* args[] )
{
SDL_Init( SDL_INIT_VIDEO );
gWindow = SDL_CreateWindow( "test", 0,0,640,480, SDL_WINDOW_SHOWN );
gRenderer = SDL_CreateRenderer(gWindow,-1,SDL_RENDERER_ACCELERATED);
SDL_Surface* x = SDL_CreateRGBSurface(0,50,50,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_Surface* y = SDL_CreateRGBSurface(0,640,480,32,0xFF,0xFF00,0xFF0000,0XFF000000);
SDL_SetRenderDrawColor(gRenderer,255,255,255,255);
SDL_RenderClear(gRenderer);
SDL_Rect a = {0,0,25,25};
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,255,0,255));
a.x = 25;a.y = 25;
SDL_FillRect(x,&a,SDL_MapRGBA(x->format,255,0,0,255));
SDL_FillRect(y,&y->clip_rect,SDL_MapRGBA(y->format,255,0,255,128));
SDL_Rect dest = {0,0,100,100};
SDL_Rect x_rect = {0,0,50,50};
SDL_SetSurfaceBlendMode(x,SDL_BLENDMODE_NONE);
SDL_BlitScaled( x, &x_rect, y, &dest );
SDL_Texture* t;
t = SDL_CreateTextureFromSurface(gRenderer,y);
SDL_RenderCopy(gRenderer,t,NULL,NULL);
SDL_RenderPresent(gRenderer);
SDL_Delay(2000);
return 0;
}
there is another problem appeared.I try to copy x into y,The x covered y entirely,even through there are transparent area in x.But if I don't use SDL_BLENDMODE_NONE,the alpha of the area copied into y will be set into 128,which is not my purpose.
Filling y with a color makes it work.
I added:
SDL_FillRect(y, &y->clip_rect, SDL_MapRGBA(x->format, 255, 0, 0, 255));
after the SDL_FillRect for x and it worked.
Some further experimentation of just filling a portion of y with alpha leads me to believe that SDL_BlitScaled isn't copying the alpha from the source surface so unless the dest surface has alpha where the destination rect is you won't see the result.
Some more experimentation shows that the default blend mode for a surface is SDL_BLENDMODE_BLEND and changing the mode for y to SDL_BLENDMODE_NONE also makes it work.

Problems rendering, single buffering-like effect

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;
}