SDL2 confusion with pointers c - c

I'm trying to program a basic game with SDL2 library and I am getting a little bit confused with a basic concept.
Basically I would like to make a function:
void quit_clean (SDL_Window *window, SDL_Renderer *renderer)
{
if (renderer != NULL)
SDL_DestroyRenderer(renderer);
if (window != NULL)
SDL_DestroyWindow(window);
exit(EXIT_FAILURE);
}
I would call this function each time there is an error so I can free the renderer and the window properly before to quit the program
e.g.
texture = SDL_CreateTextureFromSurface(renderer, tmp);
if(texture==NULL){
printf ("SDL_CreateTextureFromSurface Error: : %s\n", SDL_GetError());
quit_clean (&window, &renderer);
}
Where I am getting confused is if I need to call this function from another function how does it work ?
To be precise I would have:
My main() function where I create my *window and my *renderer
a new my_function() called from main() in which I would among other stuffs create a texture from a surface and test errors
and finally my quit_clean() function called from my_function() in case of error.
The way I see it, in order to pass my window and my renderer from main() to quit_clean() using my_function() the prototypes would be then:
void my_function (SDL_Window **window, SDL_Renderer **renderer);
void quit_clean (SDL_Window ***window, SDL_Renderer ***renderer);
Am I correct or not?
If yes then how could I call this function from main() if needed.
If I call "quit_clean (&window, &renderer);" from my main() the types are not correct anymore then.
Or maybe I could create pointers from window and renderer and pass those pointers to quit_clean(). I don't know I'm confused, I'm not sure if my thought process is correct.
Do you have any tips for this kind of situation?

You don't need the double pointer as arguments to your functions:
int my_function (SDL_Window *window, SDL_Renderer *renderer);
int quit_clean (SDL_Window *window, SDL_Renderer *renderer);
As you might have noticed, i've added a return type (int), because every function should return a result, indicating success or failure.
Secondly, it would be better not to call the quit_clean function from other functions, instead, if you encounter an error in for e.g. my_function, return an error and call the quit_clean function in the main function.
Like this:
int main()
{
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
window = SDL_CreateWindow(...);
if (window) {
renderer = SDL_CreateRenderer(window, ...);
if (renderer) {
int err = my_function(window, renderer);
if (!err) { //success: 0, error: -1
//do what is needed to be done
}
}
}
//finally clean up,
//no matter the case (either due to error or program termination)
quit_clean(window, renderer);
return 0;
}
In the quit_clean function you have to check the passed arguments (although i think that SDL checks them too, but better than sorry):
int quit_clean (SDL_Window *window, SDL_Renderer *renderer)
{
//other cleanup first
//finally
if (renderer != NULL)
SDL_DestroyRenderer(renderer);
if (window != NULL)
SDL_DestroyWindow(window);
SDL_Quit();
}
And for clarity an example of my_function:
int my_function (SDL_Window *window, SDL_Renderer *renderer)
{
if (some_condition_does_not_hold)
return -1;
//do your stuff
//never call quit_clean if something goes wrong, return either -1 or
//some other (previously defined) negative error number
//finally
return 0; //success
}

Related

GTK 3 GUI updated from separate thread text countdown in text box

First post, so will try and be brief until need to add more. Ported an app from macOS to NI LabWindows/CVI, in "C", then to port to GTK3 and trying to grasp the updating GUI from external thread concept. I've read the gnome documentation and searched on here, and everywhere, but not finding similar usage, or not grasping the updating the GUI from separate thread. I have experimented with g_idle_add() as follows.
int main(int argc, char* argv[])
{
gtk_init(&argc, &argv); // init Gtk
gtk_start_button = GTK_WIDGET(gtk_builder_get_object(builder,"start_button"));
gtk_main();
return EXIT_SUCCESS;
}
void start_button_clicked_cb(GtkWidget *widget, gpointer data)
{
printf("\nStart Button Pressed\n");
run_tests();
}
void run_tests( void )
{
GThread *start_testing_thread;
start_testing_thread = g_thread_new("", &start_testing, NULL);
}
void *start_testing (void *data)
{
pause(5);
}
void pause( double pause_time)
{
char string[33];
while( (double)pause_time > (double)0 )
{
sprintf( string, "Pausing %02.1f", pause_time );
printf(string);
//test_name( string );
g_idle_add(test_name_gui, string);
g_usleep(100000); // uSecs for 100 mSecs
pause_time -= 0.1;
}
}
void test_name_gui(gpointer user_data)
{
GtkTextBuffer* buffer = gtk_text_buffer_new(NULL);
char temp[99];
int error = -1;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (gtktextview_test_name));
sprintf(temp,"\n%s gui\n",(char*)user_data);
printf(temp);
if(!g_utf8_validate(user_data,-1,NULL))
{
error = 3;
}
gtk_text_buffer_set_text (buffer, (char*)user_data, -1);
printf("\nTest Name gui\n");
g_object_unref(buffer);
return G_SOURCE_REMOVE;
}

OpenGL glUniform1f not updating vertex shader

All the tutorials seem to indicate that I am doing things correctly, the vertex shader works, however it fails to recognize any input changes from the main program through the use of the glUniform1f function. I check glGetError after each line, there are no errors. I check glGetShaderiv and glGetShaderInfoLog, there are no issues. I am testing with OpenGL version 2.1 (unknown profile, but assuming the core profile) as reported by SDL.
#if defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)\
|| defined(__CYGWIN__)
/* Compiling for Windows */
#ifndef __WINDOWS__
#define __WINDOWS__
#endif
#include <windows.h>
#endif/* Predefined Windows macros */
#include <SDL2/SDL.h>
#include <GL/GL.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
//return type not verified
void glGenBuffers();
void glBindBuffer();
void glBufferData();
unsigned int glCreateShader();
void glShaderSource();
void glCompileShader();
void glGetShaderiv();
void glGetShaderInfoLog();
unsigned int glCreateProgram();
void glAttachShader();
void glLinkProgram();
void glGetProgramiv();
void glGetProgramInfoLog();
void glVertexAttribPointer();
void glEnableVertexAttribArray();
void glUseProgram();
void glDeleteShader();
void glGenVertexArrays();
void glBindVertexArray();
GLint glGetUniformLocation();
void glUniform1f();
void glDeleteProgram();
void glDeleteBuffers();
int fixSDLconsole() {
FILE *console = freopen("stdout.txt", "a",stdout);
if (console == NULL) {return errno;}
console = freopen("stdout.txt", "a",stderr);
if (console == NULL) {return errno;}
return 0;
}
void printGLVersionNumber() {
int majorVersion;
int minorVersion;
int profile;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile);
fprintf(stderr,"GL version %d.%d ",majorVersion,minorVersion);
switch (profile) {
case SDL_GL_CONTEXT_PROFILE_CORE: fprintf(stderr,"core (%d)\n",profile);break;
case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: fprintf(stderr,"compatibility (%d)\n",profile);break;
case SDL_GL_CONTEXT_PROFILE_ES: fprintf(stderr,"E.S. (%d)\n",profile);break;
default: fprintf(stderr, "unknown profile: %d\n",profile);break;
}
return;
}
#define checkGlError(label) {int error = glGetError();if (error != GL_NO_ERROR) {error_at_line(0,0,__FILE__,__LINE__,"error=%d", error);goto label;}}
int main(int argc, char **argv) {
SDL_Window *window = NULL;
SDL_GLContext context = NULL;
GLuint verticesGlIds[] = {0,0};
GLuint vertexShaderGlId = 0;
GLuint shaderProgramGlId = 0;
if (fixSDLconsole()) {
return errno;
}
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
error_at_line(1,0,__FILE__,__LINE__,"Unable to initialize SDL: %s",SDL_GetError());
goto error;
}
printGLVersionNumber();
window = SDL_CreateWindow("Window Title",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,640,SDL_WINDOW_OPENGL);
if (window == NULL) {
error_at_line(0,0,__FILE__,__LINE__,"Could not create window: %s", SDL_GetError());
goto error;
}
context = SDL_GL_CreateContext(window);
if (context == NULL) {
error_at_line(0,0,__FILE__,__LINE__,"Could not create OpenGL context: %s", SDL_GetError());
goto error;
}
glViewport(0,0,640,640);checkGlError(error);
glClearColor(.9f,.9f,.9f,1.f);checkGlError(error);
glEnableClientState(GL_VERTEX_ARRAY);checkGlError(error);
glEnableClientState(GL_COLOR_ARRAY);checkGlError(error);
float vertices[] = {
-.5f,0.f,0.f,
0.f,.5f,0.f,
0.f,-.5f,0.f,
0.f,.5f,0.f,
.5f,.5f,0.f,
0.f,0.f,0.f
};
float colors[] = {
1.f,0.f,0.f,//red
.5f,0.f,0.f,//red
0.f,1.f,0.f,//green
0.f,.5f,0.f,//green
0.f,0.f,1.f,//blue
0.f,0.f,.5f//blue
};
glGenBuffers(2, &verticesGlIds);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);checkGlError(error);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);checkGlError(error);
glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors, GL_STATIC_DRAW);checkGlError(error);
char *vertexShader =
"#version 120\n"\
"attribute vec3 aPos;\n"\
"uniform float i;\n"\
"void main() {\n"\
"gl_FrontColor=gl_Color;\n"\
"gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0);\n"\
"}\n";
vertexShaderGlId = glCreateShader(GL_VERTEX_SHADER);checkGlError(error);
if (vertexShaderGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"vertex shader could not be created");goto error;}
glShaderSource(vertexShaderGlId, 1, &vertexShader, NULL);checkGlError(error);
glCompileShader(vertexShaderGlId);checkGlError(error);
{
GLint success;
glGetShaderiv(vertexShaderGlId, GL_COMPILE_STATUS, &success);checkGlError(error);
if (success == GL_FALSE) {
char infoLog[512];
glGetShaderInfoLog(vertexShaderGlId, 512, NULL, infoLog);checkGlError(error);
error_at_line(0,0,__FILE__,__LINE__,"Vertex Shader problem: %s", infoLog);
goto error;
}
}
shaderProgramGlId = glCreateProgram();checkGlError(error);
if (shaderProgramGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"shader program could not be created");goto error;}
glAttachShader(shaderProgramGlId, vertexShaderGlId);checkGlError(error);
glLinkProgram(shaderProgramGlId);checkGlError(error);
{
int success;
glGetProgramiv(shaderProgramGlId, GL_LINK_STATUS, &success);checkGlError(error);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(shaderProgramGlId, 512, NULL, infoLog);checkGlError(error);
error_at_line(0,0,__FILE__,__LINE__,"Shader program problem: %s", infoLog);
}
}
glDeleteShader(vertexShaderGlId);checkGlError(error);
GLint iLocation = glGetUniformLocation(shaderProgramGlId, "i");checkGlError(error);
if (iLocation == -1) {error_at_line(0,0,__FILE__,__LINE__,"uniform i not found in shader");goto error;}
error_at_line(0,0,__FILE__,__LINE__,"iLocation: %d", iLocation);
for (int frame = 0; frame < 100; ++frame) {
glClear(GL_COLOR_BUFFER_BIT);checkGlError(error);
glUseProgram(shaderProgramGlId);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]); checkGlError(error);
glVertexPointer(3,GL_FLOAT,0,0); checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]); checkGlError(error);
glColorPointer(3,GL_FLOAT,0,0); checkGlError(error);
glUniform1f(iLocation, (float) (frame%2)); checkGlError(error);
glDrawArrays(GL_TRIANGLES, 0,sizeof(vertices)/sizeof(float)/3); checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, 0); checkGlError(error);
SDL_GL_SwapWindow(window);
SDL_Delay(100);
}
glDeleteProgram(shaderProgramGlId);
glDeleteShader(vertexShaderGlId);
glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
SDL_GL_DeleteContext(context);
SDL_Delay(3000);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
error:
glDeleteProgram(shaderProgramGlId);
glDeleteShader(vertexShaderGlId);
glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
if (context != NULL) SDL_GL_DeleteContext(context);
if (window != NULL) SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_FAILURE;
}
#if defined(__WINDOWS__)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
char *argv[1] = {(char *) 0};
return main(0, argv);
}
#endif
note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker. I don't expect this to be an issue but it is the only issue, I am aware of, that I haven't looked into, that may be causing my problems.
So you declare the function like this:
void glUniform1f();
By omitting any parameters, the compiler will assume that all arguments are of type int. For most other GL functions, this works by chance, because those arguments are just integer types in most cases anyway, but for glUniform1f, it will mean that the function argument is converted to integer, but the resulting bit-pattern is implicitely re-interpreted as GLfloat by the function since the actual prototype for glUniform1f is something like this
void glUniform1f(int location, GLfloat value);
note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker.
You shouldn't do this. The GL functions you try to access might not even be exported by the library at all. If you do not want to manually deal with loading every function pointer, you can use one of the existing OpenGL loaders.
gl_Position expects Clip-space coordinates, which are a hiper-cube of size [2w,2w,2w,w].
For vec4(x, y, z, w) if any of the [x,y,z] is outside of [-w,w] range, then the vertex is clipped.
The coordinates will be automatically converted by the GPU to NDC-space x/w, y/w, z/w, 1 (aka "perspective division") before the fragment shader.
Your GLSL code gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0); uses the uniform i.
You update it by glUniform1f(iLocation, (float) (frame%2));
First issue is frame%2. Only 0 or 1 is passed to the GPU. With your current vertices data, only two pairs of triangles should be drawn.
Second issue is that frame is a value 0 <= frame < 100. So, if you pass frame instead of frame%2, then for most values aPos.x + i/2 will fall outside the Clip space and you will see only the first two triangle-pairs, or parts of them.

Segmentation fault initializing SDL2. What am I doing wrong with memory?

This is just suppose to display a bmp image to the SDL window front buffer. I played around with the code. And I think there is something wrong with my init() function. I'm new to SDL. But there must be a problem with my pointers or something I'm missing about SDL's fucntions
EDIT: I used GDB and it turned out my close() function was the problem. I believe it was because I was freeing memory that was set to NULL? I got rid of the close fucntion and just freed mem after my delay function.
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdbool.h>
#define SCREENWIDTH 640
#define SCREENHEIGHT 480
SDL_Window *win = NULL;
SDL_Surface *scrn = NULL;
SDL_Surface *mscrn = NULL;
bool init()
{
bool suc = true;
char name[11] = "Hello SDL";
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("%s", SDL_GetError());
suc = false;
}
win = SDL_CreateWindow(name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREENWIDTH, SCREENHEIGHT, SDL_WINDOW_SHOWN);
if (win == NULL) {
printf("%s", SDL_GetError());
suc = false;
}
scrn = SDL_GetWindowSurface(win);
return suc;
}
bool loadmedia()
{
bool suc = true;
mscrn = SDL_LoadBMP("hello_world.bmp");
if (mscrn == NULL) {
printf("%s", SDL_GetError());
suc = false;
}
return suc;
}
void close()
{
SDL_FreeSurface(mscrn);
SDL_DestroyWindow(win);
SDL_Quit();
}
int main(int argc, char* args[])
{
if (!init()) {
close();
return 1;
}
if (!loadmedia()) {
close();
return 1;
}
SDL_BlitSurface(mscrn, NULL, scrn, NULL);
SDL_UpdateWindowSurface(win);
SDL_Delay(3000);
close();
return 0;
}
You should find a reasonable debugger and other tools to to find out which line is causing the error and why. Basically it boils down to using a debugger which usually comes with your IDE if you're using one, or using the very good code analysis tool, Valgrind.
If you're using gcc you can likely use gdb to debug your program easily. Here are some resources on how to help you diagnose segmentation faults:
Determine the line of C code that causes a segmentation fault?
http://www.cprogramming.com/debugging/segfaults.html
Get familiar with these tools, as they will save you countless hours in the future when you face new problems.

How to load GdkPixbuf from file in a callback function?

I'm using gtk+ 3.14 and I want to load a picture that the user chooses.
The code here correctly displays the picture but doest not seem to update
the GdkPixbuf *pixbuf. In fact, GdkPixbuf is not NULL inside the function but it
is NULL outside it. What can I do to correctly load and use pixbuf in other functions ?
Here is the callback structure :
struct callback_struct
{
GdkPixbuf *pix;
GtkWidget *img;
int height;
int width;
float scale;
};
Here is my code :
void callback_load(gpointer data)
{
struct callback_struct *passed = data;
GdkPixbuf *pixbuf = passed->pix;
GtkWidget *image = passed->img;
int h_scr = passed ->height;
int w_scr = passed->width;
float scale = passed->scale;
GtkWidget *dial_box = gtk_file_chooser_dialog_new("Choose the image to load"
,GTK_WINDOW(gtk_widget_get_toplevel(image)),
GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel",GTK_RESPONSE_CANCEL,"Open",GTK_RESPONSE_ACCEPT,NULL);
switch (gtk_dialog_run (GTK_DIALOG (dial_box)))
{
case GTK_RESPONSE_ACCEPT:
{
gchar *filename =gtk_file_chooser_get_filename
(GTK_FILE_CHOOSER (dial_box));
pixbuf = gdk_pixbuf_new_from_file(filename,NULL);
printf("%d\n",(pixbuf == 0));
GdkPixbuf *scaled_buffer = gdk_pixbuf_scale_simple
(pixbuf,h_scr*scale,w_scr*scale,GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(image),scaled_buffer);
printf("%d\n",(pixbuf == 0));
gtk_widget_destroy(dial_box);
break;
}
case GTK_RESPONSE_CANCEL:
{
gtk_widget_destroy(dial_box);
break;
}
}
}
You only modify the local pointer pixbuf: in fact passed->pix is NULL throughout the code.
You should either not use a local pointer at all (and just refer to passed->pix) , or alternatively set the structs pointer equal to the local pointer at some point after initializing it.

I am trying to initialize an SDL_Window in a function but it always fails unless I define SDL_Window*win; as a global variable

I am trying to initialize an SDL_Window in a function but it always fails unless I define SDL_Window*win; as a global variable. Here is the code:
#include<SDL2/SDL.h>
#include<stdio.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
SDL_Surface*Init(SDL_Window*win,char*title,int x,int y,int w,int h,Uint32 flags);
int main(int argc,char**argv){
SDL_Surface *screen=NULL;
SDL_Window*win=NULL;
screen=Init(win,"SDL_Test",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,0xFF,0x00,0x00));
SDL_UpdateWindowSurface(win);
SDL_Delay(2000);
}
SDL_Surface*Init(SDL_Window*win,
char*title,
int x,
int y,
int w,
int h,
Uint32 flags){
SDL_Surface*temp=NULL;
if(SDL_Init(SDL_INIT_EVERYTHING)){
printf("\nError : %s",SDL_GetError());
SDL_ClearError();
return NULL;
}
win=SDL_CreateWindow(title,x,6,w,h,flags);
if(!win){
printf("\nError: %s",SDL_GetError());
SDL_ClearError();
return NULL;
}
temp=SDL_GetWindowSurface(win);
if(!temp){
printf("\nError: %s",SDL_GetError());
SDL_ClearError();
return NULL;
}
return temp;
}
If I declare SDL_Window*win as a global variable it shows a red screen(as it should) but if
I define SDL_Window*win in main() and pass it to Init() it show a white screen(error?).
You are not updating win in the main function. In c you pass variables by value and if you change the value of a pointer ( or win in your case ) the change will not happen outside the function.
The shortest ( but not the best ) solution would be to return window pointer win and then get the surface with SDL_GetWindowSurface(win)

Resources