terrain

Real-time terrain generation using marching cubes
git clone git://git.christianermann.dev/terrain
Log | Files | Refs | README | LICENSE

commit baaa759198978be8812d1af4754ab63c3fd097dc
parent 4fe77c114d3ef9f906bd53d32232bc8d9db9f258
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sun, 11 Jul 2021 15:26:26 -0700

First triangle

Diffstat:
Ainclude/glh/buffer.h | 16++++++++++++++++
Ainclude/glh/shader.h | 16++++++++++++++++
Ashaders/basic.fs | 10++++++++++
Ashaders/basic.vs | 11+++++++++++
Asrc/buffer.c | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.c | 39+++++++++++++++++++++++++++++++++++++++
Asrc/shader.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; + } +}