Problems rendering, single buffering-like effect - c++

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

Related

Auto redraw window possible in SDL-2?

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.

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.

Inconsistent "undefined reference to..." errors when building SDL with MinGW/Code::Blocks

I have 3 independent files, two are .c files, one is .cpp.
When I try to build/run in Code::Blocks one of the .c files I get an "undefined reference to `SDL_main'" build error.
first file (let's call it SDLtest1.c) builds and runs:
//-----< includes >-----//
// Using SDL and standard IO
#include "SDL.h"
#include <stdio.h>
//-----< globals and constants >-----//
//screen dimension constants
typedef enum {
SCREEN_WIDTH = 640,
SCREEN_HEIGHT = 480,
}SCREEN_DIMENSIONS;
//-----< main >-----//
int main(int argc, char* argv[]) {
// The window we'll be rendering to
SDL_Window* window = NULL;
// The surface contained by the window
SDL_Surface* screenSurface = NULL;
// Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
printf( "SDL could not be initialized! SDL_Error: %s\n", SDL_GetError() );
}
else {
// Create Window
window = SDL_CreateWindow("SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if( window == NULL ){
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
} else {
// Get window surface
screenSurface = SDL_GetWindowSurface( window );
// Fill the surface white
SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF) );
// Update the surface
SDL_UpdateWindowSurface( window );
// Wait two seconds
SDL_Delay( 2000 );
}
}
// Destroy Window
SDL_DestroyWindow( window );
// Quit SDL subsystems
SDL_Quit();
return 0;
}
I also have a .cpp file (lets call it SDLexample.cpp) that builds and runs:
//Using SDL and standard IO
#include <SDL.h>
#include <stdio.h>
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;
bool init()
{
//Initialization flag
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
{
//Create window
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load splash image
gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
if( gHelloWorld == NULL )
{
printf( "Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
success = false;
}
return success;
}
void close()
{
//Deallocate surface
SDL_FreeSurface( gHelloWorld );
gHelloWorld = NULL;
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() )
{
printf( "Failed to load media!\n" );
}
else
{
//Apply the image
SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
//Update the surface
SDL_UpdateWindowSurface( gWindow );
//Wait two seconds
SDL_Delay( 2000 );
}
}
//Free resources and close SDL
close();
return 0;
}
But this third file (SDLtest2.c) fails to build as follows:
C:\MinGW\lib\libSDL2main.a(SDL_windows_main.o):SDL_windows_main.c|| undefined reference to `SDL_main'|
||=== Build finished: 1 errors, 0 warnings (0 minutes, 0 seconds) ===|
third file:
//-----< includes >-----//
#include "SDL.h"
#include <stdio.h>
//-----< preprocessor directives >-----//
#define TRUE 1
#define FALSE 0
typedef int BOOLEAN;
//-----< globals and constants >-----//
typedef enum {
SCREEN_WIDTH = 640,
SCREEN_HEIGHT = 480
}SCREEN_DIMENSION;
// The window we'll be rendering to
SDL_Window* gWindow = NULL;
// The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
// The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;
//-----< forward declarations >-----//
// Starts up SDL and creates window
BOOLEAN init();
// Loads media
BOOLEAN loadMedia();
// Frees media and shuts down SDL
void close();
//-----< main >-----//
int main(int argc, char* args[]) {
// Start up SDL and create window
if( !init() ) {
printf( "Failed to initialize!\n" );
}
else
{
// Load media
if( !loadMedia() ) {
printf( "Failed to load media!\n" );
}
else
{
// Apply the image
SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
// Update the surface
SDL_UpdateWindowSurface( gWindow );
// Wait two seconds
SDL_Delay( 2000 );
}
}
// Free resources and close SDL
close();
return 0;
}
//-----< function definitions >-----//
BOOLEAN init() {
// Initialization flag
BOOLEAN 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
{
// Create a window
gWindow = SDL_CreateWindow( "SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if( gWindow == NULL ) {
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetEror() );
success = FALSE;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
return success;
}
BOOLEAN loadMedia() {
// Loading success flag
BOOLEAN success = TRUE;
// Load splash image
gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
if( gHelloWorld == NULL ) {
printf( "Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
success = FALSE;
}
return success;
}
void close() {
// Deallocate surface
SDL_FreeSurface( gHelloWorld );
gHelloWorld = NULL;
// Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
I've looked over and over the third file for typos that could cause the build error and haven't found any (although I surely could have missed one). I have looked over similar forum questions but nothing has been an exact match and the fact that the other two files build and run successfully suggests to me that the problem isn't with my Code::Blocks or SDL set-up.
I know this is all a lot to look over and appreciate any help anyone can provide.