I have the following simple SDL code:
#include <SDL.h>
#include <stdbool.h>
#include <stdio.h>
// helpers
bool init(SDL_Window **win, SDL_Surface **surf) {
int const width = 800;
int const height = 600;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
return false;
}
*win = SDL_CreateWindow("Picture test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
width, height, 0);
if (*win == NULL) {
fprintf(stderr,
"Unable to create window: %s\n",
SDL_GetError());
return false;
}
*surf = SDL_GetWindowSurface(*win);
return true;
}
bool load_media(SDL_Surface **surf) {
*surf = SDL_LoadBMP("./sample.bmp");
if (*surf == NULL) {
fprintf(stderr, "Unable to load data: %s\n", SDL_GetError());
return false;
}
return true;
}
void close(SDL_Window **win, SDL_Surface **surf) {
SDL_FreeSurface(*surf);
SDL_DestroyWindow(*win);
SDL_Quit();
}
int main()
{
SDL_Window *win;
SDL_Surface *surf;
SDL_Surface *img;
if (!init(&win, &surf)) {
return EXIT_FAILURE;
}
if (!load_media(&img)) {
return EXIT_FAILURE;
}
SDL_BlitSurface(img, NULL, surf, NULL);
SDL_UpdateWindowSurface(win);
SDL_Delay(2000);
close(&win, &img);
}
My code always segfaults on close (the origin of the segfault according to GDB is the line SDL_FreeSurface(*surf)). More strangely, if I replace the call to close with its definition, this still segfaults in exactly the same place. Specifically, if I replace close(&win, &img) with:
SDL_FreeSurface(img);
SDL_DestroyWindow(win);
SDL_Quit();
the code still segfaults at exactly the same place, even though that function is not even being called. Only if I remove the entire close function does this work correctly. I am completely confused as to what could be causing this.
Please rename your function
void close(SDL_Window **win, SDL_Surface **surf)
since close is a standard C library function.
I can confirm this. Same scenario. Even with -Wall and -Wextra the compiler did not spit out a redeclaration warning. Same for open().
I need an experts' opinion if this is a gcc bug.
Solution 1: declare your close() as a static function (e.g. static close()).
Solution 2: rename your close() function to something else (e.g. my_close_foo()).
Related
Currently using SDL2, and attempting to output a basic SDL Window (Ubuntu 20.04) with the C programming language. Program runs, window does not display.
Would like to preface that I've gotten the SDL_Window to show up once before, but (possibly unrelated) after the successful integration of SDL2_gfx, there seems to be issues with the window displaying.
I've run the code both on the Eclipse IDE and in the main linux command line, same error persists, with both a clean build, and a successful compilation, but the window does not show on the screen.
See code below.
#include <stdio.h>
#include <stdlib.h>
#include <SDL2/SDL.h>
int main(int argc, char **argv) {
SDL_Window *window;
if(SDL_Init(SDL_INIT_VIDEO) < 0){
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
return 1;
}
window = SDL_CreateWindow("SDL Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_ALLOW_HIGHDPI);
if(window == NULL){
printf("SDL window failed to initialize: %s\n", SDL_GetError());
return 1;
}
SDL_Event e;
int quit = 0;
while(quit == 0){
while(SDL_PollEvent(&e)){
if(e.type == SDL_QUIT){
quit = 1;
}
if(e.type == SDL_KEYDOWN){
quit = 1;
}
if(e.type == SDL_MOUSEBUTTONDOWN){
quit = 1;
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
Few points/disclaimers: This question has been asked by MacOS users, some suggestions include putting in
if(SDL_Init(SDL_INIT_EVERYTHING) < 0)...
vs
if(SDL_Init(SDL_INIT_VIDEO) < 0)....
This has been attempted but I do not have audio support configured for SDL
Also....
SDL_WINDOW_ALLOW_HIGHDPI
Has been changed to various flags, and this has been unsuccessful.
Any advice/suggestions/solutions?
I just started coding a game using SDL2 in C, but I quickly ran into a problem : my images are not displayed on the window. I already made the following checks:
the window and the renderer are successfully created
my .bmp files are correctly loaded
the SDL_RenderCopy() function is called, and returns no error
the SDL_RenderPresent() function is called and returns no error
I'm not trying to display my images on a 0x0px surface
my image is a .bmp file
Here is some code, I hope this will help (I'm sorry it's quite disorganized):
Edit: I simplified the showed code
TrapAdventures.c (main file):
#include <SDL2/SDL.h>
#include <stdio.h>
#include "HobbesSDL.h"
#include "TrapInit.h"
#include "TrapKeyboard.h"
#define Ellipsis (return 0)
#define Pass ((void)0)
#define NullKeycode ((SDL_Keycode)0)
int main(void){
HobbesBool TrapRunning = HOBBES_TRUE;
HobbesWindow *TrapWindow;
HobbesRenderer *TrapRenderer;
if (TrapInitContext("Trap adventures", &TrapWindow, &TrapRenderer) != 0){
TrapRunning = HOBBES_FALSE;
}
HobbesSprite *TrapPlayer;
if (TrapInitSprite(&TrapPlayer, TrapRenderer) != 0)
TrapRunning = HOBBES_FALSE;
while (TrapRunning){
if (TrapGetKeyState(TrapKeySpace))//Quit program if spacebar is pressed
TrapRunning = HOBBES_FALSE;
SDL_RenderClear(TrapRenderer);
if (HobbesDisplaySprite(TrapPlayer) != 0){
printf("Error while displaying player!\n");
TrapRunning = HOBBES_FALSE;
}
SDL_RenderPresent(TrapRenderer);
SDL_Delay(50);
}
HobbesDestroySprite(TrapPlayer);
SDL_DestroyRenderer(TrapRenderer);
SDL_DestroyWindow(TrapWindow);
HobbesQuit();
printf("End!\n");
return 0;
}
The HobbesSprite type defined in HobbesSDL.h (my own (and small) library, using SDL2):
typedef struct HobbesSprite {
SDL_Renderer *renderer;
SDL_Surface *surface;
SDL_Texture *texture;
HobbesRect *rect;
HobbesHitbox *hitbox;
HobbesBool hidden;
} HobbesSprite;
Some of the functions in HobbesSDL.c that I use in this code:
#include <SDL2/SDL.h>
#include "HobbesSDL.h"
#include <errno.h>
int HobbesInit(void){
int ret = SDL_Init(SDL_INIT_VIDEO);
if (ret != 0)
fprintf(stderr, "Error while initializing SDL2: %s", SDL_GetError());
return ret;
}
int HobbesDisplaySprite(HobbesSprite *sprite){
if (SDL_RenderCopy(sprite->renderer, sprite->texture, NULL, (SDL_Rect *)sprite->rect) != 0 && !sprite->hidden){
fprintf(stderr, "Error while displaying sprite: %s\n", SDL_GetError());
fclose(stderr);
return -1;
}
return 0;
}
void HobbesUpdateWindow(HobbesRenderer *renderer){
SDL_RenderPresent(renderer);
}
TrapInit.c:
#include <SDL2/SDL.h>
#include "HobbesSDL.h"
#include "TrapInit.h"
/*These first four functions will be used to initialize the rendering context*/
int TrapInitSDL(){
return HobbesInit();
}
HobbesWindow *TrapInitWindow(const char name[]){
SDL_Window *window = SDL_CreateWindow(name, 0, 0, 1000, 1000, 0);
if (window == NULL){
fprintf(stderr, "Error while creating window: %s\n", SDL_GetError());
}
return window;
}
HobbesRenderer *TrapInitRenderer(HobbesWindow *window){
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer == NULL){
fprintf(stderr, "Error while creating renderer: %s\n", SDL_GetError());
}
return renderer;
}
int TrapInitContext(const char name[], HobbesWindow **wptr, HobbesRenderer **rptr){
//Initializes the rendering context using the above functions
int InitSDLResult = TrapInitSDL();
*wptr = TrapInitWindow(name);
*rptr = TrapInitRenderer(*wptr);
if (InitSDLResult != 0 || *wptr == NULL || *rptr == NULL)
return 1;
return 0;
}
/*The following function will be used to create every sprite needed in the game*/
int TrapInitSprite(HobbesSprite **Player, HobbesRenderer *renderer){
*Player = HobbesCreateSprite(renderer, "Images/Player.bmp", 0, 724);
if (*Player == NULL)
return 1;
return 0;
}
(I'm sorry that my code is so unclear, but I do my best :) )
My OS is MacOS Big Sur 11.6.4, my graphic card Intel Iris Pro Graphics 6200 1536 Mo, my processor is a 3,3 GHz Intel Core i7 four cores.
Finally, even thought I use the gcc command to compile, my compiler is clang (Apple made the choice to use clang by default, but the command is still gcc…).
If you need any other information, just ask in the comments and I'll answer you the best I can.
Do you have any ideas?
I did a lot of tests, and finally found the problem.
The problem was that I tried to convert a HobbesRect * to a SDL_Rect *, but I did it wrong. If you look at the code of HobbesDisplaySprite, I do something like this:
SDL_RenderCopy(sprite->renderer, sprite->texture, NULL, (SDL_Rect *)sprite->rect) //(SDL_Rect *)sprite->rect is the problem
I solved my problem using a far more explicit conversion:
SDL_RenderCopy(sprite->renderer, sprite->texture, NULL, &((SDL_Rect){sprite->rect->x, sprite->rect->y, sprite->rect->w, sprite->rect->h}))
Thank you all for your interest in my problem! I'll try to put less code in my question next time ;) !
I'm trying to figure out a way to store all my dependent libraries in a sub folder, say /libs, and my executable outside of this folder. From what I can tell, I need to then add this library folder into the system PATH or add some code such as HINSTANCE hDLL = LoadLibrary(".\\libs\\mydll.DLL"); into my source (correct me if I'm wrong here, I'm not very sure about this).
However, the problem is, I also would like to be able to compile the same source code on Linux, without having to modify it every time I change from one OS to another. Is this possible? How can I do that in C? If possible, can you guy show me the most standard way to do it in the industry?
I know having all my DLLs outside together with my executable will solve this problem instantly, but that's just avoiding the problem altogether and I'm interested to learn more about this topic.
For example, here I have a small C code that help me initialize some SDL2 facilities:
#include <stdio.h>
#include <stdlib.h>
#include "SDL2\SDL.h"
#include "SDL2\SDL_messagebox.h"
#include "SDL2\SDL_image.h"
#include "SDL2\SDL_ttf.h"
#define MAX_KEYBOARD_KEYS 350
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
typedef struct {
SDL_Renderer *renderer;
SDL_Window *window;
int keyboard[MAX_KEYBOARD_KEYS];
} App;
App app;
void initSDL() {
/*
Procedure to initiate SDL2, SDL_Image, and SDL_ttf
Log errors and quit the program if failed.
*/
int rendererFlags, windowFlags, imgFlags;
rendererFlags = SDL_RENDERER_ACCELERATED;
windowFlags = 0;
imgFlags = IMG_INIT_PNG | IMG_INIT_JPG;
//initiate SDL stuff. If return < 0 error occured
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Failed to initate SDL: %s", SDL_GetError());
exit(1);
}
//create a window
app.window = SDL_CreateWindow("pong", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, windowFlags);
if (!app.window) {
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to create window: %s", SDL_GetError());
exit(1);
}
//set hint for SDL
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
//create a renderer
app.renderer = SDL_CreateRenderer(app.window, -1, rendererFlags);
if (!app.renderer) {
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to create renderer: %s", SDL_GetError());
exit(1);
}
//init IMG
if (IMG_Init(imgFlags) == 0) {
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to initialize SDL_Image: %s", SDL_GetError());
exit(1);
}
//init TTF
if (TTF_Init() == -1) {
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to initialize SDL_ttf: %s", SDL_GetError());
exit(1);
}
}
void cleanUp() {
/*
Procedure to quit all facilities gracefully and announce a normal exit of the program
*/
SDL_DestroyRenderer(app.renderer);
SDL_DestroyWindow(app.window);
IMG_Quit();
TTF_Quit();
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Exited normally");
SDL_Quit();
}
int main(int argc, char* argv[]) {
/*
Possibly here we will have that HINSTANCE hDLL = LoadLibrary(".\\libs\\mydll.DLL");
to deal with all the DLLs I have in the libs folder
*/
initSDL();
atexit(cleanUp);
exit(0);
}
Now fortunately this code can be compiled both on Windows (mingw32) and Linux if I so choose myself. What I'm worrying about is that, after adding Windows-specific codes, my source will lose such liberty.
I'm trying to make SDL2 use the root X window to display things, but it doesn't seem to work - the window doesn't get changed in any way. Also, the whole program doesn't quit after the SDL_Delay() for some reason. Is it not possible? Am I doing something wrong?
#include <SDL.h>
#include <X11/Xlib.h>
#include <stdio.h>
// clang -lSDL2 -lX11 -I/usr/include/SDL2 -Weverything x11.c -o x11
int main(void)
{
Display *x11_d;
int x11_s;
Window x11_w;
SDL_Window *w;
SDL_Renderer *r;
x11_d = XOpenDisplay(NULL);
if(!x11_d) {
fprintf(stderr, "couldn't open display\n");
return 1;
}
x11_s = DefaultScreen(x11_d);
x11_w = RootWindow(x11_d, x11_s);
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "couldn't initialize SDL: %s\n", SDL_GetError());
return 1;
}
w = SDL_CreateWindowFrom((void *)x11_w);
XCloseDisplay(x11_d);
if(!w) {
fprintf(stderr, "couldn't attach to the root X11 window: %s\n", SDL_GetError());
return 1;
}
r = SDL_CreateRenderer(w, -1, 0);
SDL_SetRenderDrawColor(r, 255, 0, 0, 255);
SDL_RenderClear(r);
SDL_RenderPresent(r);
SDL_Delay(5700);
SDL_Quit();
return 0;
}
You're closing the X Display right after you create the SDL window, so you lose the connection. That obviously isn't helping but you also left out about 95% of the code required to get X working. Tutorial here.
The following basic SDL2 code taken from a tutorial website is causing some strange trouble :
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define SCREENH 768
#define SCREENW 1366
SDL_Window *window = NULL;
SDL_Surface *screenSurface = NULL;
SDL_Surface *windowSurface = NULL;
int init_SDL() {
int success = 0;
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL could not initialize! ");
printf("SDL_Error: %s\n",SDL_GetError());
success = -1;
}
else {
window = SDL_CreateWindow("SDL2_Tutorial02",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREENW,SCREENH,SDL_WINDOW_SHOWN);
if(window == NULL) {
printf("Window could not be created! ");
printf("SDL Error: %s\n",SDL_GetError());
}
else {
screenSurface = SDL_GetWindowSurface(window);
}
}
return success;
}
int loadMedia() {
int success = 0;
windowSurface = SDL_LoadBMP("Images/Hallo.bmp");
if(windowSurface == NULL) {
printf("Unable to load image! ");
printf("SDL Error: %s\n",SDL_GetError());
success = -1;
}
return success;
}
void close() {
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_DestroyWindow(window);
window = NULL;
SDL_Quit();
}
int main(int argc,char *argv[]) {
assert(init_SDL() == 0);
assert(loadMedia() == 0);
SDL_BlitSurface(windowSurface,NULL,screenSurface,NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(3000);
close();
exit(EXIT_SUCCESS);
}
As soon as SDL_Quit(), placed in close(), is invoked I receive a memory access error. Using GDB the following is revealed:
49 SDL_Quit();
(gdb) n
Program received signal SIGBUS, Bus error.
0x00007ffff68a5895 in ?? () from /usr/lib/x86_64-linux-gnu/libX11.so.6
(gdb)
The strange about that is when I place SDL_Quit() outside of close() like this:
void close() {
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_DestroyWindow(window);
window = NULL;
}
int main(int argc,char *argv[]) {
assert(init_SDL() == 0);
assert(loadMedia() == 0);
SDL_BlitSurface(windowSurface,NULL,screenSurface,NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(3000);
close();
SDL_Quit();
exit(EXIT_SUCCESS);
}
all things are fine. SDL_Quit() works without error. Why does it cause a SIGBUS Error when I invoke SDL_Quit() in another function ?
EDIT: This code was compiled on ubuntu 14.04 with gcc and the following compile command
gcc -g3 -o tutorial tutorial.c `sdl2-config --cflags --libs`
Your function close() is in conflict with an internal SDL function with the same name causing weird behavior (actually, it is the libc standard close() syscall called by SDL).
Rename your function and it should be fine.