I am writing a program that displays an animation that is dependent on the size of the display. In order to get this to work with multiple displays, I have an array of display_data objects:
struct window_data
{
SDL_Rect bounds;
SDL_Window *window;
};
and initialize these for each display:
int numdisplays = SDL_GetNumVideoDisplays();
std::vector< window_data > screens( numdisplays );
for( int i = 0 ; i < numdisplays ; ++i )
{
SDL_GetDisplayBounds( i, &( screens[ i ].bounds ) );
screens[ i ].window
= SDL_CreateWindow( "Display", screens[ i ].bounds.x,
screens[ i ].bounds.y, screens[ i ].bounds.w,
screens[ i ].bounds.h, SDL_WINDOW_FULLSCREEN );
}
This works fine as long as my mouse cursor is in the primary display, but if I start the program with the cursor in the secondary display, it will draw both windows in the secondary display, resulting in only the second window being visible. This behavior seems to depend only on the location of the cursor and not the terminal window from which I run the program.
I have verified that the same display numbers and bounds are found regardless of the cursor location, so I am perplexed by the variation in the program behavior. Is this the intended behavior of SDL2, or a bug? In either case, could anyone suggest a workaround?
EDIT: The mouse dependency shows up on Debian with XFCE. I have tried this on Windows as well and it outputs both windows on the second monitor, regardless of the mouse position.
You can use the SDL_WINDOWPOS_UNDEFINED_DISPLAY macro in the position arguments to SDL_CreateWindow, in combination with the SDL_WINDOW_FULLSCREEN parameter.
Something like:
SDL_CreateWindow(
"Window Name",
SDL_WINDOWPOS_UNDEFINED_DISPLAY(display),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(display),
0,
0,
SDL_WINDOW_FULLSCREEN),
The macro is not well documented, but you can see how is works clearly by reading the source code.
Try SDL_WINDOW_BORDERLESS instead of SDL_WINDOW_FULLSCREEN.
I'm not sure if multiple fullscreen windows can meaningfully coexist, especially once you factor in input grabs.
Try something like this:
#include <SDL2/SDL.h>
#include <vector>
struct window_data
{
SDL_Rect bounds;
SDL_Window *window;
SDL_Renderer* renderer;
};
int main( int argc, char **argv )
{
if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
return EXIT_FAILURE;
std::vector< window_data > screens( SDL_GetNumVideoDisplays() );
for( size_t i = 0; i < screens.size(); ++i )
{
window_data& screen = screens[ i ];
SDL_GetDisplayBounds( i, &screen.bounds );
screen.window = SDL_CreateWindow
(
"Display",
screen.bounds.x, screen.bounds.y,
screen.bounds.w, screen.bounds.h,
SDL_WINDOW_BORDERLESS
);
screen.renderer = SDL_CreateRenderer( screen.window, 0, SDL_RENDERER_ACCELERATED );
SDL_ShowWindow( screen.window );
}
bool running = true;
while( running )
{
SDL_Event ev;
while( SDL_PollEvent( &ev ) )
{
if( ev.type == SDL_QUIT ) running = false;
if( ev.type == SDL_KEYUP &&
ev.key.keysym.sym == SDLK_ESCAPE ) running = false;
}
for( size_t i = 0; i < screens.size(); ++i )
{
window_data& screen = screens[ i ];
SDL_SetRenderDrawColor( screen.renderer, 255, 0, 0, 255 );
SDL_RenderFillRect( screen.renderer, NULL );
SDL_RenderPresent( screen.renderer );
}
SDL_Delay( 33 );
}
for( size_t i = 0; i < screens.size(); ++i )
{
window_data& screen = screens[ i ];
SDL_DestroyRenderer( screen.renderer );
SDL_DestroyWindow( screen.window );
}
SDL_Quit();
return EXIT_SUCCESS;
}
Related
Im running this on MacOS 10.12 using Xcode 8.3.3 with SDL2 installed via Homebrew as Dylibs.
Below is some slightly modified sample code from lazy foo.
I just added a second texture gTexture2 and the function loadMedia2 to be able to reproduce the issue. The second time IMG_Load is executed it crashes with the following message:
EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
Searching on how to solve a "General Protection Fault" problem did also not get me further, the crash seems to happen inside SDL. I probably really misunderstand here something that leads to this issue and would really welcome any help.
The really confusing thing is, it does not crash always, only about 2 of 3 times.
The crash seem to happen inside SDL_AllocFormat_REAL ():
Here is the code sample.
/*This source code copyrighted by Lazy Foo' Productions (2004-2015)
and may not be redistributed without written permission.*/
//Using SDL, SDL_image, standard IO, and strings
#include <SDL.h>
#include <SDL_image.h>
#include <stdio.h>
#include <string>
//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();
//Loads individual image as texture
SDL_Texture* loadTexture( std::string path );
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The window renderer
SDL_Renderer* gRenderer = NULL;
//Current displayed texture
SDL_Texture* gTexture = NULL;
SDL_Texture* gTexture2 = 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
{
//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( "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
{
//Create renderer for window
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
if( gRenderer == NULL )
{
printf( "Renderer could not be created! 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;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load PNG texture
gTexture = loadTexture( "../assets/player.png" );
if( gTexture == NULL )
{
printf( "Failed to load texture image!\n" );
success = false;
}
return success;
}
bool loadMedia2()
{
//Loading success flag
bool success = true;
//Load PNG texture
gTexture2 = loadTexture( "../assets/scene_main/background.png" );
if( gTexture == NULL )
{
printf( "Failed to load texture image!\n" );
success = false;
}
return success;
}
void close()
{
//Free loaded image
SDL_DestroyTexture( gTexture );
SDL_DestroyTexture( gTexture2 );
gTexture = NULL;
gTexture2 = NULL;
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
SDL_Texture* loadTexture( std::string path )
{
//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
{
//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() );
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
return newTexture;
}
int main( int argc, char* args[] )
{
//Start up SDL and create window
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
//Load media
if( !loadMedia() || !loadMedia2() )
{
printf( "Failed to load media!\n" );
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
//Clear screen
SDL_RenderClear( gRenderer );
//Render texture to screen
SDL_RenderCopy( gRenderer, gTexture, NULL, NULL );
//Update screen
SDL_RenderPresent( gRenderer );
}
}
}
//Free resources and close SDL
close();
return 0;
}
Little Update:
I've tried it on windows, there it runs completely fine. So I guess the issue is related to MacOs.
I already tried to reinstall all libraries.
I'm using C++14.
The solution
Well its just half of a solution its more a workaround.
Thanks to #Sahib Yar he pointed out to try to put the images in the same directory. Which resolves the issue.
But I think this is really weird, you should be able to load resources from different directories or at least subdirectory.
The final question
Now I would really love an explanation why we can't load images from multiple directories using SDL on MacOS. Is that just a bug, known thing or did I make a big mistake?
It seems that you are not destroying texture2 that is not needed.
SDL_DestroyTexture( gTexture );
SDL_DestroyTexture( gTexture2 );
gTexture = NULL;
gTexture2 = NULL;
In this lazyfoo tutorial, it is mentioned that
In our clean up function, we have to remember to deallocate our
textures using SDL_DestroyTexture.
Edit 1:
Try to put all your images in the same directory.
Edit 2:
It is not related to directory in MacOS From this tutorial, it seems like compiler is doing some optimization with std::string path as the std::string is mutable.
Try to clear the std::string path object at end of function to clear up all the memory reserved by its objects.
add this line.
std::string().swap(path);
Your issue is a dangling pointer. EXC_BAD_ACCESS is the CPU moaning that you are addressing non-existent memory or memory which is outside of your access rights area. The cause is a lack of reatainment of an object which causes early deallocation and then is overwritten. At which time (which may be delayed), the pointer will point to garbage whose dereference causes an EXC_BAD_ACCESS to be thrown.
Edit 3:
It is not something related to SDL2. After Googling, I have found that in Xcode, everything is eventually packed into 1 single directory. I have found multiple questions regarding this. It may be something related to folder reference and groups. To my guess it could be something related to blue folders. If this is the case you can consult this answer and use accordingly for SDL.
Maybe it's just me being dumb, but I'm sure this should work.
#include <SDL2/SDL.h>
#include <GL/glew.h>
struct Display
{
SDL_Window* window;
SDL_GLContext context;
};
Display* init()
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE );
SDL_Window* window = SDL_CreateWindow( "Ice Engine",
800, 600,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SDL_WINDOW_OPENGL );
if ( !window )
{
printf( "%s\n", SDL_GetError() );
return nullptr;
}
SDL_GLContext context = SDL_GL_CreateContext( window );
if ( !context )
{
printf( "%s\n", SDL_GetError() );
return nullptr;
}
glewExperimental = GL_TRUE;
if ( glewInit() != GLEW_OK )
return nullptr;
return new Display{ window, context };
}
int main( int argc, char** argv )
{
Display* display = init();
bool running = true;
SDL_Event e;
while( running )
{
while( SDL_PollEvent( &e ) )
if ( e.type == SDL_QUIT )
running = false;
SDL_GL_SwapWindow( display->window );
}
delete display;
SDL_Quit();
}
I probably shouldn't be using new and delete and such, but this was just a quick setup to get my project going. The problem is it compiles just fine, but when I run it I get this error:
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 1 (X_CreateWindow)
Value in failed request: 0x0
Serial number of failed request: 155
Current serial number in output stream: 168
I've tried without setting the OpenGL context versions, but I just get the same error.
I tried switching to GLFW3 and it all works just fine. It creates me a window and a OpenGL 3.3 core profile context. So it seems to be a problem with SDL2. I'm running ubuntu 15.10 and I installed it via the command line with: sudo apt install libsdl2-dev.
You are calling SDL_CreateWindow incorrectly. You have mixed up the x, y and width, height settings. The right way would be:
SDL_Window* window = SDL_CreateWindow("Ice Engine",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800,
600,
SDL_WINDOW_OPENGL );
See SDL_CreateWindow reference. Other than that, your code looks fine.
I was making a game using Code::Blocks, and came across the Segmentation fault error. I have looked through other questions here and couldn't find anything that helped. I have a Sprite class that represents the basic objects in the game and a Window class that controls the display to the screen of the game. I ran the debugger and it gave me the error at the line return image; from the getImage() method below.
SDL_Surface* Sprite::getImage() {
return image;
}
I call the following setImage() method in the constructor for Sprite, and I verified that SDL_ConvertSurface did not return NULL.
void Sprite::setImage(string 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 {
image = SDL_ConvertSurface( loadedSurface, surface->format, NULL );
if( image == NULL ) {
printf( "Unable to optimize image %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
SDL_FreeSurface( loadedSurface );
}
}
I call the method getImage() in mainloop() of Window, as shown below, where sprites is declared as Sprite* sprites[10];:
void Window::mainloop() {
bool quit = false;
SDL_Event e;
while( !quit ) {
while( SDL_PollEvent( &e ) != 0 ) {
if( e.type == SDL_QUIT ) {
quit = true;
}
}
SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, red, green, blue ) );
for (int i = 0; i < spritesNum; i++) {
SDL_BlitScaled( sprites[spritesNum]->getImage() , NULL, screenSurface, sprites[spritesNum]->getRect() );
}
SDL_UpdateWindowSurface( window );
}
}
You are probably indexing out of range here
for (int i = 0; i < spritesNum; i++) {
SDL_BlitScaled( sprites[spritesNum]->getImage() , NULL, screenSurface, sprites[spritesNum]->getRect() );
}
I assume you wanted to use your counter i?
for (int i = 0; i < spritesNum; i++) {
SDL_BlitScaled( sprites[i]->getImage() , NULL, screenSurface, sprites[i]->getRect() );
}
Otherwise if your array sprites is of length spritesNum you are indexing out of range, and doing so spritesNum number of times.
In any case, you should at least confirm you aren't dereferencing a null pointer here
sprites[i]->getImage()
I have SDL version 1.2.15 install in code block-12.11 when i tries to use it with SDL2-image extension i ran into a certain problem .When i click 'run' a window pop up and vanishes instanly .I followed the instruction of installing the sdl2-image extension from this video http://lazyfoo.net/SDL_tutorials/lesson03/windows/codeblocks/index.php
.Here is what i did
i transfer all the files under lib in sdl2-image extension to lib folder of the codeblock istallation directory and all the files under include i.e-sdl2 folder of sdl2-image extension to include directory of the codeblock and all the files under lib of sdl2-image extension to the exe directory of the program made.
when i run it there is no error but the windows appear and vanishes instanly the code of my program is
#include "SDL/SDL.h"
#include "SDL2/SDL_image.h"
#include <string>
//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//The surfaces
SDL_Surface *background = NULL;
SDL_Surface *foo = NULL;
SDL_Surface *screen = 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 image 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 image
optimizedImage = SDL_DisplayFormat( loadedImage );
//Free the old image
SDL_FreeSurface( loadedImage );
//If the image was optimized just fine
if( optimizedImage != NULL )
{
//Map the color key
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );
//Set all pixels of color R 0, G 0xFF, B 0xFF to be transparent
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
}
}
//Return the optimized image
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
//Temporary rectangle to hold the offsets
SDL_Rect offset;
//Get the offsets
offset.x = x;
offset.y = y;
//Blit the surface
SDL_BlitSurface( source, NULL, destination, &offset );
}
bool init()
{
//Initialize all SDL subsystems
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return 1;
}
//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 1;
}
//Set the window caption
SDL_WM_SetCaption( "Foo says \"Hello!\"", NULL );
//If everything initialized fine
return true;
}
bool load_files()
{
//Load the background image
background = load_image( "background.png" );
//If the background didn't load
if( background == NULL )
{
return false;
}
//Load the stick figure
foo = load_image( "foo.png" );
//If the stick figure didn't load
if( foo == NULL )
{
return false;
}
return true;
}
void clean_up()
{
//Free the surfaces
SDL_FreeSurface( background );
SDL_FreeSurface( foo );
//Quit SDL
SDL_Quit();
}
int main( int argc, char* args[] )
{
//Quit flag
bool quit = false;
//Initialize
if( init() == false )
{
return 1;
}
//Load the files
if( load_files() == false )
{
return 1;
}
//Apply the surfaces to the screen
apply_surface( 0, 0, background, screen );
apply_surface( 240, 190, foo, screen );
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
//While the user hasn't quit
while( quit == false )
{
//While there's events to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if( event.type == SDL_QUIT )
{
//Quit the program
quit = true;
}
}
}
//Free the surfaces and quit SDL
clean_up();
return 0;
}
is something wrong with the code or installation process or is sdl2-image-2.0.0 extension not compatible with sdl-1.2.15? help
You will either need to use an old version of SDL_Image from here: http://www.libsdl.org/projects/SDL_image/release-1.2.html or you will need to update to SDL2.0.1. I would recommend moving to SDL 2.0.1 because it is a much more modern graphics library.
I am new to C++ and SDL; I am trying to add a new SDL extension libary using instructions found here: http://www.lazyfoo.net/SDL_tutorials/lesson03/windows/devcpp/index.php
But I get these errors:
3 C:\Documents and Settings\Edmund\My Documents\C++\myprojects\SDL\SDLevent.cpp SDL/SDL_image.h: No such file or directory.
C:\Documents and Settings\Edmund\My Documents\C++\myprojects\SDL\SDLevent.cpp In function `SDL_Surface* load_image(std::string)':
28 C:\Documents and Settings\Edmund\My Documents\C++\myprojects\SDL\SDLevent.cpp `IMG_Load' undeclared (first use this function)
and then a bunch of unqualified ids.
This is my code:
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include <string>
//Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//The surfaces
SDL_Surface *image = NULL;
SDL_Surface *screen = NULL;
//The event structure that will be used
SDL_Event event;
SDL_Surface *load_image( std::string filename )
{
//The image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized image 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 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 )
{
//Temporary rectangle to hold the offsets
SDL_Rect offset;
//Get the offsets
offset.x = x;
offset.y = y;
//Blit the surface
SDL_BlitSurface( source, NULL, 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( "Event test", NULL );
//If everything initialized fine
return true;
}
bool load_files()
{
//Load the image
image = load_image( "astyle.bmp" );
//If there was an error in loading the image
if( image == NULL )
{
return false;
}
//If everything loaded fine
return true;
}
void clean_up()
{
//Free the image
SDL_FreeSurface( image );
//Quit SDL
SDL_Quit();
}
//Initialize
if( init() == false )
{
return 1;
}
//Load the files
if( load_files() == false )
{
return 1;
}
//Apply the surface to the screen
apply_surface( 0, 0, image, screen );
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
//While the user hasn't quit
while( quit == false )
{
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if( event.type == SDL_QUIT )
{
//Quit the program
quit = true;
}
}
}
//Free the surface and quit SDL
clean_up();
return 0;
}
It is pretty much identical to what is on the tutorial so it should not be a problem with the code. I have followed the Instructions on Lazy foo to the letter, I have put all of the files in the right place and linked to them so i do not know what I am doing wrong.
Your compiler can't find the SDL/SDL_image.h header, that leads to all those 'undeclared' errors.
Maybe you skipped Step 2 in the linked instructions.
Are you sure you have the SDL_Image function at all? What IDE are you using?
If its visual studio make sure you have linked the following:
Also make sure you have downloaded the latest SDL_Image files from http://www.libsdl.org/projects/SDL_image/
Another possible issue is that you havent placed the SDL_Image DLL files in the correct place.
you should use
#include "SDL.h"
#include "SDL_image.h"
and make sure that you have put the sdl include folder in your include directory