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.
Related
I am trying to create an SDL window which is by itself fully transparent, but when an image is rendered onto it, the image is fully opaque and the alpha channel of the image is conserved (so the transparent pixels of the image remain transparent). So the result would be just an image on the screen, with no container around it (Imagine sticking a real-life sticker on your screen)
So here is the simplified code for that:
#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_syswm.h>
#include <iostream>
#include <Windows.h>
#include <string>
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Texture* image;
int imageWidth = 0;
int imageHeight = 0;
bool init()
{
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
return false;
}
//Set texture filtering to linear
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf("Warning: Linear texture filtering not enabled!");
}
//Create window
window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 500, 300, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS);
if (window == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
return false;
}
//Create renderer for window
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == NULL)
{
printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
return false;
}
//Initialize renderer color
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
//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());
return false;
}
return true;
}
bool loadImage(const std::string& path)
{
//The final texture
SDL_Texture* newImage = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load(path.c_str());
if (!loadedSurface)
{
printf("Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError());
return false;
}
//Create texture from surface pixels
newImage = SDL_CreateTextureFromSurface(renderer, loadedSurface);
if (!newImage)
{
printf("Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
return false;
}
imageWidth = loadedSurface->w;
imageHeight = loadedSurface->h;
//Get rid of old loaded surface
SDL_FreeSurface(loadedSurface);
image = newImage;
return true;
}
void displayImage()
{
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderClear(renderer);
SDL_SetWindowSize(window, imageWidth, imageHeight);
SDL_Rect renderQuad = { 0, 0, imageWidth, imageHeight };
SDL_RenderCopy(renderer, image, NULL, &renderQuad);
SDL_RenderPresent(renderer);
}
// Makes a window transparent by setting a transparency color.
bool windowColorKey(SDL_Window* window, COLORREF colorKey) {
SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version); // Initialize wmInfo
SDL_GetWindowWMInfo(window, &wmInfo);
HWND hWnd = wmInfo.info.win.window;
// Change window type to layered
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// Set transparency color
return SetLayeredWindowAttributes(hWnd, colorKey, 0, LWA_COLORKEY);
}
int main(int argc, char* args[]) {
// Initialize SDL: Create a window and renderer
init();
// Load the image
loadImage("example.png");
// Color key the background of the window (magenta)
windowColorKey(window, RGB(255, 0, 255));
// Render the image on the widnow with magenta for backround color
displayImage();
// Check for events
bool windowActive = true;
SDL_Event event;
while (windowActive)
{
while (SDL_PollEvent(&event) != 0)
{
if (event.type == SDL_QUIT || event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { windowActive = false; }
}
}
return 0;
}
Using SDL_SetWindowOpacity() won't work because all the elements of the window transparent too.
For now the only way I know to achieve this goal is using color keying, but unfortunately it doesn't work that well, since some of the images will contain the color you use for color keying, and additionally the images will have a small border of the color you used for color keying all around the image. It's thin but annoying.
I am thinking of using the features of a layered window in some other way but cannot find or understand how to.
So, the question is how to make the window itself fully transparent, while having full control over the transparency of the elements of the window?
Currently I am essentially recreating the original Mario for an assignment. I haave it setup so that the game uses a ScreenManager and currently by default loads Level1 when run. Level1 then loads up the background and the character, both using a Texture2D class I made earlier. If one of these is loaded and the other is commented out then they render to the screen fine and look normal, however if I render both of them to the screen it begins to flicker continuously.
Level1 Render() Function:
void GameScreenLevel1::Render()
{
mBackgroundTexture->Render(Vector2D(), SDL_FLIP_NONE);
myCharacter->Render();
}
Texture2D Class:
#include <iostream>
#include <SDL_image.h>
#include "Texture2D.h"
using namespace::std;
Texture2D::Texture2D(SDL_Renderer* renderer)
{
mRenderer = renderer;
SDL_Texture* mTexture = NULL;
SDL_Texture* vTexture = NULL;
int mWidth = 0;
int mHeight = 0;
}
Texture2D::~Texture2D()
{
Free();
mRenderer = NULL;
}
bool Texture2D::LoadFromFile(string path)
{
Free();
//Loadtheimage
SDL_Surface* pSurface = IMG_Load(path.c_str());
if (pSurface != NULL)
{
SDL_SetColorKey(pSurface, SDL_TRUE, SDL_MapRGB(pSurface->format, 0, 0xFF, 0xFF));
mTexture = SDL_CreateTextureFromSurface(mRenderer, pSurface);
if (mTexture == NULL)
{
cout << "Unable to create texture from surface. Error:" << SDL_GetError() << endl;
}
else
{
mWidth = pSurface->w;
mHeight = pSurface->h;
}
}
else
{
cout << "Unable to create texture from surface. Error: " << IMG_GetError() << endl;
}
//vTexture = mTexture;
return mTexture != NULL;
}
void Texture2D::Render(Vector2D newPosition, SDL_RendererFlip flip, double angle)
{
//clear the screen
SDL_SetRenderDrawColor(mRenderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(mRenderer);
//set where to render the texture
SDL_Rect renderLocation = {newPosition.x, newPosition.y, mWidth, mHeight};
//render to screen
SDL_RenderCopyEx(mRenderer, mTexture, NULL, &renderLocation, 0, NULL, flip);
SDL_RenderPresent(mRenderer);
}
void Texture2D::Free()
{
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
SDL_DestroyTexture(vTexture);
vTexture = NULL;
mHeight = 0;
mWidth = 0;
}
}
It seems to me the code is getting caught up clearing the screen and rendering the textures over and over each frame causing the flickering and because of having multiple textures on screen it slows the process to the point its visible but im unsure how to correct the issue.
It seems that in your render function you are clearing the screen for every texture you’re loading, so the screen is cleared, then the first texture is loaded and rendered, but before the second texture is also rendered, the screen is cleared again, and instead of the second texture being overlayed on top of the first, it would flicker between the two textures
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.
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).