diff --git a/opengl/.gitignore b/opengl/.gitignore new file mode 100644 index 0000000..aafba12 --- /dev/null +++ b/opengl/.gitignore @@ -0,0 +1,2 @@ +a.out +gl \ No newline at end of file diff --git a/opengl/Makefile b/opengl/Makefile new file mode 100644 index 0000000..f05bf6e --- /dev/null +++ b/opengl/Makefile @@ -0,0 +1,5 @@ +CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -g +LDFLAGS = -lSDL2 -lGLEW -lGL + +gl: main.c + gcc ${CFLAGS} ${LDFLAGS} main.c -o gl \ No newline at end of file diff --git a/opengl/README b/opengl/README new file mode 100644 index 0000000..e18e538 --- /dev/null +++ b/opengl/README @@ -0,0 +1,2 @@ +since I've never worked with opengl I made this folder as a little test environment +for an SDL-OpenGL renderer \ No newline at end of file diff --git a/opengl/fragment.glsl b/opengl/fragment.glsl new file mode 100644 index 0000000..a91c2b6 --- /dev/null +++ b/opengl/fragment.glsl @@ -0,0 +1,9 @@ +#version 330 + +out vec4 color; + +void main() +{ + // set the color for each vertex to white + color = vec4(1.0f, 1.0f, 1.0f, 1.0f); +} \ No newline at end of file diff --git a/opengl/main.c b/opengl/main.c new file mode 100644 index 0000000..bd32ed1 --- /dev/null +++ b/opengl/main.c @@ -0,0 +1,254 @@ +#define _POSIX_C_SOURCE 200809l + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define GLSL_VERT_SHADER "vertex.glsl" +#define GLSL_FRAG_SHADER "fragment.glsl" + + +struct { + SDL_Window *w; + SDL_GLContext *gl; + GLuint gl_vertbuffer; + GLuint gl_program; +} ren = {0}; + +#define VNUM(s, e) ((sizeof(s)/sizeof(s[0]))/e) +float vert[] = { + 0.75f, 0.75f, 0.0f, 1.0f, + -0.75f, -0.75f, 0.0f, 1.0f, + 0.75f, -0.75f, 0.0f, 1.0f, +}; + + +// copy the vertex buffer from system to video memory +void ren_initvertbuffer() +{ + // generate a buffer id + glGenBuffers(1, &ren.gl_vertbuffer); + // tell opengl that we want to work on that buffer + glBindBuffer(GL_ARRAY_BUFFER, ren.gl_vertbuffer); + // copy the vertex data into the gpu memory, GL_STATIC_DRAW tells opengl + // that the data will be used for drawing (DRAW) and it will only be modified + // once (STATIC) + glBufferData(GL_ARRAY_BUFFER, sizeof(vert), &vert, GL_STATIC_DRAW); + // set the data to generic vertex buffer, and bind it as input to the vertex + // shader with an index of zero + // vertex attribute is the OpenGL name given to a set of vertices which are + // given as input to a vertext shader, in a shader an array of vertices is + // always referred to by index and not by pointer or other manners, indices + // go from 0 to 15 + int vertindex = 0; + glEnableVertexAttribArray(vertindex); + // set the format of each vertex, in this case each vertex is made of 4 + // coordinates, x y z w, where w is the clip coordinate + glVertexAttribPointer(vertindex, 4, GL_FLOAT, GL_FALSE, 0, 0); + // reset the object bind so not to create errors + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + + +void map_file(const char **str, int *size, const char *fname) +{ + FILE *fp = fopen(fname, "r"); + *size = lseek(fileno(fp), 0, SEEK_END); + *str = mmap(0, *size, PROT_READ, MAP_PRIVATE, fileno(fp), 0); + fclose(fp); +} + + +// print shader compilation errors +int debug_shader(GLuint shader) +{ + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status != GL_FALSE) + return 0; + + GLint log_length; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); + + GLchar *log_str = malloc((log_length + 1)*sizeof(GLchar)); + glGetShaderInfoLog(shader, log_length, NULL, log_str); + + const char *shader_type_str = NULL; + GLint shader_type; + glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type); + switch(shader_type) { + case GL_VERTEX_SHADER: shader_type_str = "vertex"; break; + case GL_GEOMETRY_SHADER: shader_type_str = "geometry"; break; + case GL_FRAGMENT_SHADER: shader_type_str = "fragment"; break; + } + + fprintf(stderr, "Compile failure in %s shader:\n%s\n", shader_type_str, log_str); + free(log_str); + return -1; +} + + +// print program compilation errors +int debug_program(GLuint prog) +{ + GLint status; + glGetProgramiv (prog, GL_LINK_STATUS, &status); + if (status != GL_FALSE) + return 0; + + GLint log_length; + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length); + + GLchar *log_str = malloc((log_length + 1)*sizeof(GLchar)); + glGetProgramInfoLog(prog, log_length, NULL, log_str); + fprintf(stderr, "Linker failure: %s\n", log_str); + free(log_str); + + return -1; +} + + +void ren_initshaders() +{ + GLuint gl_vertshader, gl_fragshader; + + // initialize the vertex shader and get the corresponding id + gl_vertshader = glCreateShader(GL_VERTEX_SHADER); + if (!gl_vertshader) + err(-1, "Could not create the vertex shader"); + + // map the shader file into memory + const char *vshader_str = NULL; + int vshader_size; + map_file(&vshader_str, &vshader_size, GLSL_VERT_SHADER); + + // get the shader into opengl + glShaderSource(gl_vertshader, 1, &vshader_str, NULL); + // compile the shader + glCompileShader(gl_vertshader); + if (debug_shader(gl_vertshader)) + exit(EXIT_FAILURE); + + // do the same for the fragment shader + // FIXME: make this a function + gl_fragshader = glCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragshader) + err(-1, "Could not create the vertex shader"); + + // map the shader file into memory + const char *fshader_str = NULL; + int fshader_size; + map_file(&fshader_str, &fshader_size, GLSL_FRAG_SHADER); + + // get the shader into opengl + glShaderSource(gl_fragshader, 1, &fshader_str, NULL); + // compile the shader + glCompileShader(gl_fragshader); + if (debug_shader(gl_fragshader)) + exit(EXIT_FAILURE); + + // create the main program object, it is an amalgamation of all shaders + ren.gl_program = glCreateProgram(); + // attach the shaders to the program (set which shaders are present) + glAttachShader(ren.gl_program, gl_vertshader); + glAttachShader(ren.gl_program, gl_fragshader); + // then link the program (basically the linking stage of the program) + glLinkProgram(ren.gl_program); + if (debug_program(ren.gl_program)) + exit(EXIT_FAILURE); + + // after linking the shaders can be detached and the source freed from + // memory since the program is ready to use + glDetachShader(ren.gl_program, gl_vertshader); + glDetachShader(ren.gl_program, gl_fragshader); + munmap((void *)vshader_str, vshader_size); + munmap((void *)fshader_str, fshader_size); + + // now tell opengl to use the program + glUseProgram(ren.gl_program); +} + + +void ren_drawvertbuffer() +{ + glBindBuffer(GL_ARRAY_BUFFER, ren.gl_vertbuffer); + glDrawArrays(GL_TRIANGLES, 0, VNUM(vert, 4)); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + + +int w_height(SDL_Window *win) +{ + int h; + SDL_GetWindowSize(win, NULL, &h); + return h; +} + + +int w_width(SDL_Window *win) +{ + int w; + SDL_GetWindowSize(win, &w, NULL); + return w; +} + + +int main (void) +{ + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); + SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); + + ren.w = SDL_CreateWindow("test", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 500, 500, SDL_WINDOW_OPENGL ); + + // create the OpenGL context + ren.gl = SDL_GL_CreateContext(ren.w); + if (ren.gl == NULL) + err(-1, "Failed to create OpenGL context: %s", SDL_GetError()); + + // initialize glew, this library gives us the declarations for most GL + // functions, in the future it would be cool to do it manually + GLenum glew_err = glewInit(); + if (glew_err != GLEW_OK) + err(-1, "Failed to initialize GLEW: %s", glewGetErrorString(glew_err)); + + ren_initvertbuffer(); + ren_initshaders(); + + // event loop and drawing + SDL_Event ev = {0}; + int running = 1; + do { + SDL_WaitEvent(&ev); + switch (ev.type) { + case SDL_QUIT: running = 0; break; + default: break; + } + + glViewport(0, 0, w_width(ren.w), w_height(ren.w)); + glClearColor(1.f, 0.f, 1.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + + ren_drawvertbuffer(); + + SDL_GL_SwapWindow(ren.w); + + } while(running); + + SDL_GL_DeleteContext(ren.gl); + SDL_DestroyWindow(ren.w); + SDL_Quit(); + + return 0; +} diff --git a/opengl/vertex.glsl b/opengl/vertex.glsl new file mode 100644 index 0000000..9371b7a --- /dev/null +++ b/opengl/vertex.glsl @@ -0,0 +1,10 @@ +#version 330 + +// use the input ("in") vertices from index zero +layout(location = 0) in vec4 position; + +void main() +{ + // simply copy teh output position + gl_Position = position; +} \ No newline at end of file