commit baaa759198978be8812d1af4754ab63c3fd097dc
parent 4fe77c114d3ef9f906bd53d32232bc8d9db9f258
Author: Christian Ermann <christianermann@gmail.com>
Date: Sun, 11 Jul 2021 15:26:26 -0700
First triangle
Diffstat:
7 files changed, 277 insertions(+), 0 deletions(-)
diff --git a/include/glh/buffer.h b/include/glh/buffer.h
@@ -0,0 +1,16 @@
+#ifndef GLH_BUFFER_H
+#define GLH_BUFFER_H
+
+#include "glad/glad.h"
+#include <stdlib.h>
+
+// Create a vertex buffer of 'size' bytes filled with the data at 'first'
+GLuint createVertexBuffer(size_t size, GLfloat* first, GLenum mode);
+
+// Create an index buffer of 'size' bytes filled with the data 'first'
+GLuint createIndexBuffer(size_t size, GLuint* first, GLenum mode);
+
+GLuint createVertexArray(GLuint vertex_buffer, GLuint index_buffer,
+ int attribute_count, int* attribute_sizes);
+
+#endif
diff --git a/include/glh/shader.h b/include/glh/shader.h
@@ -0,0 +1,16 @@
+#ifndef GLH_SHADER_H
+#define GLH_SHADER_H
+
+#include "glad/glad.h"
+
+typedef struct {
+ GLuint program;
+ const char* vert_filename;
+ const char* frag_filename;
+} Shader;
+
+Shader Shader_create(const char* vert_filename, const char* frag_filename);
+
+void Shader_reload(Shader* shader);
+
+#endif
diff --git a/shaders/basic.fs b/shaders/basic.fs
@@ -0,0 +1,10 @@
+#version 330 core
+
+in vec4 position;
+
+out vec4 out_color;
+
+void main()
+{
+ out_color = vec4(1.0, 0.8, 0.6, 1.0);
+}
diff --git a/shaders/basic.vs b/shaders/basic.vs
@@ -0,0 +1,11 @@
+#version 330 core
+
+layout(location = 0) in vec3 in_position;
+
+out vec4 position;
+
+void main()
+{
+ position = vec4(in_position, 1.0);
+ gl_Position = position;
+}
diff --git a/src/buffer.c b/src/buffer.c
@@ -0,0 +1,53 @@
+#include "glh/buffer.h"
+
+GLuint createVertexBuffer(size_t size, GLfloat* first, GLenum mode)
+{
+ GLuint vertex_buffer;
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, size, first, mode);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ return vertex_buffer;
+}
+
+GLuint createIndexBuffer(size_t size, GLuint* first, GLenum mode)
+{
+ GLuint index_buffer;
+ glGenBuffers(1, &index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, first, mode);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ return index_buffer;
+}
+
+GLuint createVertexArray(GLuint vertex_buffer, GLuint index_buffer,
+ int attribute_count, int* attribute_sizes)
+{
+ GLuint vertex_array;
+ glGenVertexArrays(1, &vertex_array);
+ glBindVertexArray(vertex_array);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+
+ size_t vertex_size = 0;
+ for (int i = 0; i < attribute_count; i++)
+ {
+ vertex_size += attribute_sizes[i];
+ }
+ vertex_size *= sizeof(GLfloat);
+
+ size_t offset = 0;
+ for (int i = 0; i < attribute_count; i++)
+ {
+ glVertexAttribPointer(i, attribute_sizes[i], GL_FLOAT, GL_FALSE,
+ vertex_size, (GLvoid*)offset);
+ glEnableVertexAttribArray(i);
+ offset += attribute_sizes[i] * sizeof(GLfloat);
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
+
+ glBindVertexArray(0);
+
+ return vertex_array;
+}
diff --git a/src/main.c b/src/main.c
@@ -1,5 +1,10 @@
+#include "glh/buffer.h"
+#include "glh/shader.h"
+
#include "glad/glad.h"
+#include <cglm/cglm.h>
+
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <stdbool.h>
@@ -42,6 +47,29 @@ int main(int argc, char** argv)
glClearColor(0.4f, 0.4f, 0.6f, 1.0f);
+ GLuint vertex_buffer = createVertexBuffer(3 * sizeof(vec3), NULL,
+ GL_STATIC_DRAW);
+ vec3 vertices[] = {
+ {-0.5, -0.5, 0.0},
+ { 0.0, 0.5, 0.0},
+ { 0.5, -0.5, 0.0}
+ };
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, 3 * sizeof(vec3), vertices);
+
+ GLuint index_buffer = createIndexBuffer(3 * sizeof(GLuint), NULL,
+ GL_STATIC_DRAW);
+ GLuint indices[] = {0, 1, 2};
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3 * sizeof(GLuint), indices);
+
+ int vertex[] = { 3 };
+ GLuint vertex_array = createVertexArray(vertex_buffer, index_buffer, 1,
+ vertex);
+
+ Shader shader = Shader_create("shaders/basic.vs", "shaders/basic.fs");
+ glUseProgram(shader.program);
+
SDL_Event window_event;
while (true)
{
@@ -51,9 +79,20 @@ int main(int argc, char** argv)
{
break;
}
+ switch (window_event.key.keysym.sym)
+ {
+ case SDLK_r:
+ Shader_reload(&shader);
+ glUseProgram(shader.program);
+ break;
+ }
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glBindVertexArray(vertex_array);
+ glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
+
SDL_GL_SwapWindow(window);
}
diff --git a/src/shader.c b/src/shader.c
@@ -0,0 +1,132 @@
+#include "glh/shader.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static char* stringFromFile(const char* filename)
+{
+ // Open file.
+ FILE* fp = fopen(filename, "r");
+ if (!fp)
+ {
+ fprintf(stderr, "ERROR: Could not open file '%s'\n", filename);
+ return NULL;
+ }
+
+ // Calculate the length of the file.
+ fseek(fp, 0, SEEK_END);
+ long size = ftell(fp);
+ rewind(fp);
+
+ // Read file to string.
+ char* string = (char*)malloc(size + 1);
+ if (string)
+ {
+ fread(string, 1, size, fp);
+ string[size] = '\0';
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: Failed to allocate string for file '%s'\n",
+ filename);
+ }
+ fclose(fp);
+ return string;
+}
+
+static GLuint createAndCompileShader(const char* shader_string,
+ GLenum shader_type)
+{
+ GLuint shader = glCreateShader(shader_type);
+ glShaderSource(shader, 1, &shader_string, NULL);
+ glCompileShader(shader);
+
+ // Handle errors.
+ GLint is_compiled;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled);
+ if (is_compiled == GL_FALSE)
+ {
+ GLint size;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
+ char* string = (char*)malloc(size);
+ glGetShaderInfoLog(shader, size, &size, string);
+ fprintf(stderr, "ERROR: Failed to compile shader: %s\n", string);
+ glDeleteShader(shader);
+ return 0;
+ }
+
+ return shader;
+}
+
+static GLuint createAndLinkProgram(GLuint vertex_shader,
+ GLuint fragment_shader)
+{
+ GLuint program = glCreateProgram();
+ glAttachShader(program, vertex_shader);
+ glAttachShader(program, fragment_shader);
+ glLinkProgram(program);
+
+ // Handle errors.
+ GLint is_linked;
+ glGetProgramiv(program, GL_LINK_STATUS, &is_linked);
+ if (is_linked == GL_FALSE)
+ {
+ GLint size;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size);
+ char* string = (char*)malloc(size);
+ glGetProgramInfoLog(program, size, &size, string);
+ fprintf(stderr, "ERROR: Failed to link program: %s\n", string);
+ glDeleteProgram(program);
+ return 0;
+ }
+
+ glDetachShader(program, vertex_shader);
+ glDetachShader(program, fragment_shader);
+
+ return program;
+}
+
+static GLuint createProgramFromFiles(const char* vertex_shader_filename,
+ const char* fragment_shader_filename)
+{
+ char* vertex_shader_string = stringFromFile(vertex_shader_filename);
+ GLuint vertex_shader = createAndCompileShader(vertex_shader_string,
+ GL_VERTEX_SHADER);
+ if (vertex_shader == 0) return 0;
+
+ char* fragment_shader_string = stringFromFile(fragment_shader_filename);
+ GLuint fragment_shader = createAndCompileShader(fragment_shader_string,
+ GL_FRAGMENT_SHADER);
+ if (fragment_shader == 0) return 0;
+
+ GLuint program = createAndLinkProgram(vertex_shader, fragment_shader);
+
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+
+ return program;
+}
+
+Shader Shader_create(const char* vertex_shader_filename,
+ const char* fragment_shader_filename)
+{
+ GLuint program = createProgramFromFiles(vertex_shader_filename,
+ fragment_shader_filename);
+
+ Shader shader = { program, vertex_shader_filename,
+ fragment_shader_filename };
+
+ return shader;
+}
+
+void Shader_reload(Shader* shader)
+{
+ GLuint reloaded_program = createProgramFromFiles(shader->vert_filename,
+ shader->frag_filename);
+
+ if (reloaded_program != 0)
+ {
+ glDeleteProgram(shader->program);
+ shader->program = reloaded_program;
+ }
+}