So I got into SDL2 with C++ quite recently and I did this very simple code :
int main(int argc, char** argv)
{
SDL_Event *event;
bool done = false;
if(SDL_Init(SDL_INIT_VIDEO) != 0)
{
std::cerr << "Problèmes pour initialiser la SDL : " << SDL_GetError() << std::endl;
return 1;
}
SDL_Window *window = 0;
window = SDL_CreateWindow("Mopion", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
if(window == 0)
{
done = true;
}
while(!done)
{
while(SDL_PollEvent(event))
{
switch(event->type)
{
case SDL_QUIT:
done = true;
break;
case SDL_KEYUP:
if(event->key.keysym.sym == SDLK_q)
{
done = true;
}
break;
default:
break;
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
While that code executes at first quite well, when I hit the "Q" key, the window closes but I got a Windows Error Window saying that "My program stopped working." which is not very convenient.
Using the debugger, I found that everything is fine until SDL_Quit() is called.
Anyone has any idea why this is going on ?
Thanks a lot !
You don't reserve memory for your SDL_Event, and are most probably corrupting your stack. Declare it as automatic and pass it by address to SDL_PollEvent().
You're using uninitialized pointer:
SDL_Event *event;
And you need to fix some errors:
1. If SDL_CreateWindow() returns 0, it means that there is no window and you must not use SDL_DestroyWindow().
2. You're using events, so you should call SDL_Init() like this: SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS).
Related
I want to create a little program, which should draw some Math Functions.
At first a just wrote the code, that should create a little Window, that should just be visisble until I hit the X at the window.
#include <iostream>
#include <SDL2/SDL.h>
SDL_Window* window;
SDL_Renderer* renderer;
bool running = true;
bool init() {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) return false;
window = SDL_CreateWindow("Visual Functions", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 100, 200, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if(window == NULL) return false;
if(renderer == NULL) return false;
std::cout << "App and SDL init success" << std::endl;
return true;
}
void onEvent(SDL_Event* event) {
switch (event->type)
{
case SDL_QUIT:
running = false;
break;
default:
break;
}
}
void loop() {
SDL_Event* event;
while(SDL_PollEvent(event)) onEvent(event);
}
void cleanUp() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
int main(int, char**) {
if(!init()) {
std::cout << "SDL or/and App init failed" << std::endl;
exit(-1);
}
while(running) loop();
cleanUp();
}
But the window pops so fast up and again down, that I couldn't even see it and in the command is at first App and SDL init success but then there stands Segmentation fault.
In a other code, which has the same Initialization and Loop code runs very well and everything is displayed displayed normally (at least for the SDL part).
I found out with some debug messages, that the loop comes not to the Event Function, but also not to the end of the Loop Function, so the problem is SDL_PollEvent(event), but what is the prolem and how to I fix it ?
You never create the SDL_Event struct that you are using:
void loop() {
SDL_Event* event;
while(SDL_PollEvent(event)) onEvent(event);
}
should be this
void loop() {
SDL_Event event;
while(SDL_PollEvent(&event)) onEvent(&event);
}
In the following code:
#include <iostream>
#include "SDL.h"
using namespace std;
int main(int argc, char** argv)
{
SDL_Surface* screenSurface = nullptr;
SDL_Surface* image = nullptr;
SDL_Window* window = nullptr;
const Uint8* keystate;
SDL_Rect offset;
offset.x = 100;
offset.y = 200;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
cout << "Window initialization error: " << SDL_GetError();
}
else
{
window = SDL_CreateWindow("game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
bool isRunning = true;
SDL_Event ev;
//game loop
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0)
{
if (ev.type == SDL_QUIT)
isRunning = false;
}
keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_W])
{
offset.y -= 1;
}
else if (keystate[SDL_SCANCODE_A])
{
offset.x -= 1;
}
else if (keystate[SDL_SCANCODE_S])
{
offset.y += 1;
}
else if (keystate[SDL_SCANCODE_D])
{
offset.x += 1;
}
screenSurface = SDL_GetWindowSurface(window);
image = SDL_LoadBMP("world.bmp");
SDL_BlitSurface(image, NULL, screenSurface, &offset);
SDL_UpdateWindowSurface(window);
cout << SDL_GetError() << endl;
}
}
SDL_FreeSurface(image);
SDL_DestroyWindow(window);
image = nullptr;
window = nullptr;
SDL_Quit();
return 0;
}
I get an error, saying: "SDL_UpperBlit: passed a NULL surface error." But the error did not occur until I went from using a switch statement in the while loop for SDL_PollEvent, to just using if statements using SDL_SCANCODE_ in the isRunning while loop. So the error does not occur instantly, but after a short while, like 10 seconds or so. So I am able to move around the world.bmp with WASD for a short while, then I get the error "SDL_UpperBlit: passed a NULL surface error.".
What's the solution for this?
image = SDL_LoadBMP("world.bmp");
This loads world.bmp from the disk, creates a brand new surface and stores the image inside. You never destroy this surface, and you don't check for errors either.
As you're running this once per frame, SDL quickly runs out of resources, SDL_LoadBMP returns NULL to signal it, and you pass that NULL to SDL_BlitSurface.
Only load your resources once, and take care of destroying them at the right time. C++ has smart pointers and RAII to do that for you.
i've installed SDL to develop a program, and while on the test phase for this lib, the compiled code does not execute, and i mean it won't even open the cmd box. The weird thing is, it occasionally executes.
I'm using Eclipse Hellios with minGW32 and i686-w64-mingw32 on windows10.
My test code is:
#include <iostream>
#include <Windows.h>
#include <SDL2/SDL.h>
int main(int, char**)
{
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) return 1;
SDL_Window *window = SDL_CreateWindow("", 300, 100, 1024, 800, SDL_WINDOW_OPENGL);
if (window == NULL)
{
std::cout << "SDL init Error: " << SDL_GetError() << std::endl;
return 1;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface *background = SDL_LoadBMP("Resources/Lilothyn.bmp");
if (background == NULL)
{
SDL_ShowSimpleMessageBox(0, "Background init error", SDL_GetError(), window);
return 1;
}
if (renderer == NULL)
{
SDL_ShowSimpleMessageBox(0, "Renderer init error", SDL_GetError(), window);
}
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, background);
if (texture == NULL)
{
SDL_ShowSimpleMessageBox(0, "Texture init error", SDL_GetError(), window);
}
SDL_RenderPresent(renderer);
SDL_Event event;
bool running = true;
while(running)
{
SDL_PollEvent(&event);
switch(event.type)
{
case SDL_QUIT:
running = false;
SDL_DestroyTexture(texture);
SDL_FreeSurface(background);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
break;
default: break;
}
}
return 0;
}
the odd thing is, i previously had "SDL_LoadBMP("Resources/TommyBMP.bmp");" and it executed properly. Changing a string shouldn't make the program stop working, both files are at the Debug/Resources folder so it can't be a case of not finding them...
note: further testing shows that a simple "hello world" has the same issue, so the problem will likely not be from SDL.
"help me obi wan, you're my only hope".
I have this simple code for SDL.
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
using namespace std;
int main(int argc, char * argv[]){
if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
return 1;
}
SDL_Window * win = SDL_CreateWindow("Window", 0, 0, 1920, 1080, SDL_WINDOW_FULLSCREEN_DESKTOP);
if(win == nullptr){
return 1;
}
SDL_Quit();
return 0;
}
None of this shows a window, I have error checked everything. It was working previously, but now it just opens and closes. I'm running on Xcode, if that helps.
Like the others state, your program terminates immediately so the window should "flash" momentarily. You can have the window appear for a few seconds by using SDL_Delay:
SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if (win == nullptr){
std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
SDL_Quit();
return 1;
}
SDL_Delay(2000);
SDL_DestroyWindow(win);
SDL_Quit();
And remember to call SDL_DestroyWindow.
A while(true) {} loop will just cause your program to freeze. You probably want something like the following so that it listens for events, and you can close the window at your leisure.
SDL_Event e;
bool quit = false;
while (!quit){
while (SDL_PollEvent(&e)){
if (e.type == SDL_QUIT){
quit = true;
}
if (e.type == SDL_KEYDOWN){
quit = true;
}
if (e.type == SDL_MOUSEBUTTONDOWN){
quit = true;
}
}
}
Can someone write up a source for a program that just has a "game loop", which just keeps looping until you press Esc, and the program shows a basic image. Heres the source I have right now but I have to use SDL_Delay(2000); to keep the program alive for 2 seconds, during which the program is frozen.
#include "SDL.h"
int main(int argc, char* args[]) {
SDL_Surface* hello = NULL;
SDL_Surface* screen = NULL;
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
hello = SDL_LoadBMP("hello.bmp");
SDL_BlitSurface(hello, NULL, screen, NULL);
SDL_Flip(screen);
SDL_Delay(2000);
SDL_FreeSurface(hello);
SDL_Quit();
return 0;
}
I just want the program to be open until I press Esc. I know how the loop works, I just don't know if I implement inside the main() function, or outside of it. I've tried both, and both times it failed. If you could help me out that would be great :P
Here is a complete and working example. Instead of using a frame-time regulation you can also use SDL_WaitEvent.
#include <SDL/SDL.h>
#include <cstdlib>
#include <iostream>
using namespace std;
const Uint32 fps = 40;
const Uint32 minframetime = 1000 / fps;
int main (int argc, char *argv[])
{
if (SDL_Init (SDL_INIT_VIDEO) != 0)
{
cout << "Error initializing SDL: " << SDL_GetError () << endl;
return 1;
}
atexit (&SDL_Quit);
SDL_Surface *screen = SDL_SetVideoMode (640, 480, 32, SDL_DOUBLEBUF);
if (screen == NULL)
{
cout << "Error setting video mode: " << SDL_GetError () << endl;
return 1;
}
SDL_Surface *pic = SDL_LoadBMP ("hello.bmp");
if (pic == NULL)
{
cout << "Error loading image: " << SDL_GetError () << endl;
return 1;
}
bool running = true;
SDL_Event event;
Uint32 frametime;
while (running)
{
frametime = SDL_GetTicks ();
while (SDL_PollEvent (&event) != 0)
{
switch (event.type)
{
case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE)
running = false;
break;
}
}
if (SDL_GetTicks () - frametime < minframetime)
SDL_Delay (minframetime - (SDL_GetTicks () - frametime));
}
SDL_BlitSurface (pic, NULL, screen, NULL);
SDL_Flip (screen);
SDL_FreeSurface (pic);
SDL_Delay (2000);
return 0;
}
Tried with something like
SDL_Event e;
while( SDL_WaitEvent(&e) )
{
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) break;
}
? You can find many tutorials and example out there; just a fast-search example.
Added note: WaitEvent "freezes" the program so you can't do anything .. you just wait; other waiting technics can be desired (as PollEvent, or WaitEvent again after the initializtion of a timer).
Since you're already using SDL, you could use the SDL_PollEvent function to run an event loop, checking to see if the key press event was ESC. Looks like this would be along the lines of mySDL_Event.key.keysym.sym == SDLK_ESCAPE.
#include <conio.h>
...
while (!kbhit())
{
hello = SDL_LoadBMP("hello.bmp");
SDL_BlitSurface(hello, NULL, screen, NULL);
SDL_Flip(screen);
}
...