polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 48c9d306969745e809ede5865a1bdd88d2f02f85
parent 2848cdbace72999a9e453f9f487ffdc8bb3d402e
Author: William Casarin <jb55@jb55.com>
Date:   Fri,  2 Nov 2018 17:35:39 -0700

bunch of stuff, fixed shader reloading

Diffstat:
MMakefile | 2+-
Metc/shaders/profile | 1+
Metc/shaders/shadervars.glsl | 8--------
Metc/shaders/standard_vtxos.glsl | 9++++-----
Metc/shaders/terrain.g.glsl | 5++---
Metc/shaders/terrain.tc.glsl | 29++++++++++++++++-------------
Metc/shaders/terrain.te.glsl | 27++++++++++++++-------------
Metc/shaders/terrain.v.glsl | 8+++++---
Metc/shaders/test.f.glsl | 11++++++-----
Metc/shaders/vertex-color.glsl | 3+--
Msrc/game.c | 2+-
Msrc/geometry.c | 13+++++++++++--
Msrc/geometry.h | 4+++-
Msrc/render.c | 43+++++++++++++++----------------------------
Msrc/shader.c | 104++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/shader.h | 6++++--
Msrc/ui.c | 2+-
Msrc/update.c | 5+++--
18 files changed, 157 insertions(+), 125 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,7 @@ NAME ?= polyadvent BIN ?= $(NAME) PREFIX ?= /usr/local DEFS= -DGLFW_INCLUDE_NONE -DDEBUG -CFLAGS = $(DEFS) -ggdb -Ofast -I src -Wall -Werror -Wextra -std=c99 \ +CFLAGS = $(DEFS) -ggdb -O -I src -Wall -Werror -Wextra -std=c99 \ -Wno-unused-function \ -Wno-unused-parameter \ -Wno-unused-variable \ diff --git a/etc/shaders/profile b/etc/shaders/profile @@ -1 +1,2 @@ + #version 440 core diff --git a/etc/shaders/shadervars.glsl b/etc/shaders/shadervars.glsl @@ -4,11 +4,3 @@ vec3 normal; vec3 position; vec4 shadow_coord; vec3 frag_pos; - -// out flat vec3 v_color; -// out vec3 v_color_smooth; -// out vec3 v_ray; -// out vec3 v_normal; -// out vec3 v_position; -// out vec4 v_shadow_coord; -// out vec3 v_frag_pos; diff --git a/etc/shaders/standard_vtxos.glsl b/etc/shaders/standard_vtxos.glsl @@ -1,6 +1,5 @@ vec4 v4_pos = vec4(position, 1.0); -vertex.normal = normal; -vertex.color_smooth = vertex.color = color; -vertex.shadow_coord = depth_mvp * v4_pos; -vertex.position = v4_pos.xyz; -vertex.frag_pos = (world * v4_pos).xyz; +data_out.normal = normal; +data_out.color_smooth = data_out.color = color; +data_out.shadow_coord = depth_mvp * v4_pos; +data_out.frag_pos = (world * v4_pos).xyz; diff --git a/etc/shaders/terrain.g.glsl b/etc/shaders/terrain.g.glsl @@ -28,9 +28,8 @@ void main() { // vertex.shadow_coord = vertices[i].shadow_coord; // vertex.frag_pos = vertices[i].frag_pos; - gl_Position = mvp * gl_in[i].gl_Position; - vertex.position = gl_Position.xyz; - // gl_Position = vec4(vertices[i].position, 1.0); + // gl_Position = mvp * vec4(400.0 + i * 50.0, 300.0 + i * 50.0, 200.0 + i * 50.0, 1.0); + gl_Position = mvp * vec4(vertices[i].position, 1.0); EmitVertex(); } diff --git a/etc/shaders/terrain.tc.glsl b/etc/shaders/terrain.tc.glsl @@ -2,15 +2,15 @@ layout(vertices = 3) out; -in shader_datab { +in shader_data { #include shadervars.glsl -} vertex[]; +} data_in[]; -out shader_dataz { +out shader_data { #include shadervars.glsl -} tc_vertices[]; +} data_out[]; -#include uniforms.glsl +// #include uniforms.glsl // uniform float TessLevelInner; // uniform float TessLevelOuter; @@ -18,18 +18,21 @@ out shader_dataz { void main() { - tc_vertices[gl_InvocationID].position = vertex[gl_InvocationID].position; - tc_vertices[gl_InvocationID].color = vertex[gl_InvocationID].color; - tc_vertices[gl_InvocationID].color_smooth = vertex[gl_InvocationID].color_smooth; - tc_vertices[gl_InvocationID].normal = vertex[gl_InvocationID].normal; - - gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; - const float inner = 5.0; - const float outer = 8.0; + + // gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + const float inner = 1.0; + const float outer = 2.0; + if (gl_InvocationID == 0) { gl_TessLevelInner[0] = inner; gl_TessLevelOuter[0] = outer; gl_TessLevelOuter[1] = outer; gl_TessLevelOuter[2] = outer; } + + // data_out[gl_InvocationID] = data_in[gl_InvocationID]; + data_out[gl_InvocationID].position = data_in[gl_InvocationID].position; + data_out[gl_InvocationID].color = data_in[gl_InvocationID].color; + data_out[gl_InvocationID].color_smooth = data_in[gl_InvocationID].color_smooth; + data_out[gl_InvocationID].normal = data_in[gl_InvocationID].normal; } diff --git a/etc/shaders/terrain.te.glsl b/etc/shaders/terrain.te.glsl @@ -2,13 +2,13 @@ layout(triangles, equal_spacing, cw) in; -in shader_dataz { +in shader_data { #include shadervars.glsl -} tc_vertices[]; +} data_in[]; out shader_data { #include shadervars.glsl -} vertex; +} data_out; #include uniforms.glsl @@ -18,16 +18,17 @@ out shader_data { void main() { - vertex.color = tc_vertices[0].color; - vertex.color_smooth = tc_vertices[0].color_smooth; - vertex.normal = tc_vertices[0].normal; - vertex.shadow_coord = depth_mvp * tc_vertices[0].shadow_coord; - - vec4 v = gl_TessCoord.x * gl_in[0].gl_Position; - + gl_TessCoord.y * gl_in[1].gl_Position; - + gl_TessCoord.z * gl_in[2].gl_Position; + vec4 v = gl_TessCoord.x * vec4(data_in[0].position, 1.0); + + gl_TessCoord.y * vec4(data_in[1].position, 1.0); + + gl_TessCoord.z * vec4(data_in[2].position, 1.0); // tePatchDistance = gl_TessCoord; - vertex.frag_pos = (world * v).xyz; gl_Position = mvp * v; - vertex.position = gl_Position.xyz; + + data_out.position = gl_Position.xyz; + data_out.color = data_in[0].color; + data_out.color_smooth = data_in[0].color_smooth; + data_out.normal = data_in[0].normal; + data_out.shadow_coord = depth_mvp * data_in[0].shadow_coord; + data_out.frag_pos = (world * v).xyz; + } diff --git a/etc/shaders/terrain.v.glsl b/etc/shaders/terrain.v.glsl @@ -7,9 +7,11 @@ in vec3 normal; #include uniforms.glsl -out shader_datab { +out shader_data { + #include shadervars.glsl -} vertex; + +} data_out; void main() { @@ -41,5 +43,5 @@ void main() #include standard_vtxos.glsl gl_Position = v4_pos; - vertex.position = gl_Position.xyz; + data_out.position = gl_Position.xyz; } diff --git a/etc/shaders/test.f.glsl b/etc/shaders/test.f.glsl @@ -1,3 +1,4 @@ + #include profile out vec4 frag_color; @@ -23,11 +24,11 @@ void main() { // + color_smooth * smoothness; vec3 color = standard_light(vertex.color, vertex.position, vertex.normal); - if (fog_on) { - vec3 fog = apply_fog(color, length(v_ray), camera_position, v_ray); - // vec3 fog = depth_fog(color, shadow_sample); - color = fog; - } + // if (fog_on) { + // vec3 fog = apply_fog(color, length(v_ray), camera_position, v_ray); + // // vec3 fog = depth_fog(color, shadow_sample); + // color = fog; + // } if (light_dir.z > 0.0 && shadow_sample.z < vertex.shadow_coord.z ) { float factor = 1.0/dot(light_dir, vec3(0.0, 0.0, 1.0)); diff --git a/etc/shaders/vertex-color.glsl b/etc/shaders/vertex-color.glsl @@ -6,7 +6,7 @@ in vec3 color; out shader_data { #include shadervars.glsl -} vertex; +} data_out; #include uniforms.glsl @@ -14,6 +14,5 @@ out shader_data { void main() { #include standard_vtxos.glsl - gl_Position = mvp * v4_pos; } diff --git a/src/game.c b/src/game.c @@ -40,7 +40,7 @@ void game_init(struct game *game, int width, int height) { mat4 *light_dir = res->light_dir; int ok = 0; - const double size = 10000; + const double size = 1000; terrain->settings = (struct perlin_settings){ .depth = 1, diff --git a/src/geometry.c b/src/geometry.c @@ -43,10 +43,19 @@ void bind_geometry(struct geometry *geom, struct attributes *attrs) { check_gl(); } -void render_geometry(struct geometry *geom, struct attributes *attrs) +void render_geometry(struct geometry *geom, struct attributes *attrs, + struct gpu_program *program) { + int has_tess_shader = + get_program_shader(program, GL_TESS_EVALUATION_SHADER) != NULL; + + int type = GL_TRIANGLES; + if (has_tess_shader) { + glPatchParameteri(GL_PATCH_VERTICES, 3); + type = GL_PATCHES; + } bind_geometry(geom, attrs); - glDrawElements(GL_TRIANGLES, + glDrawElements(type, geom->num_indices, /* count */ GL_UNSIGNED_INT, /* type */ (void*)0 /* element array buffer offset */ diff --git a/src/geometry.h b/src/geometry.h @@ -4,6 +4,7 @@ #include "common.h" #include "buffer.h" +#include "shader.h" struct buffer_geometry { struct vbo vertex; @@ -24,7 +25,8 @@ struct geometry { float *tex_coords; }; -void render_geometry(struct geometry *geom, struct attributes *); +void render_geometry(struct geometry *geom, struct attributes *, + struct gpu_program *current_program); void bind_geometry(struct geometry *geom, struct attributes *); void init_geometry(struct geometry *geom); void make_buffer_geometry(struct geometry *geom); diff --git a/src/render.c b/src/render.c @@ -106,11 +106,11 @@ init_gl(struct resources *resources, int width, int height) { /* { &terrain_vertex, &fragment, &terrain_tc, &terrain_teval, */ /* &terrain_geom }; */ - struct shader *terrain_shaders[] = - { &terrain_vertex, &fragment, &terrain_tc, &terrain_teval }; - /* struct shader *terrain_shaders[] = */ - /* { &terrain_vertex, &fragment, &terrain_geom }; */ + /* { &terrain_vertex, &fragment, &terrain_tc, &terrain_teval }; */ + + struct shader *terrain_shaders[] = + { &terrain_vertex, &fragment, &terrain_geom }; /* struct shader *terrain_shaders[] = */ /* { &terrain_vertex, &fragment }; */ @@ -256,8 +256,13 @@ void render (struct game *game, struct render_config *config) { , &game->test_resources.player }; - int terrain_program = game->test_resources.programs[TERRAIN_PROGRAM].handle; - int default_program = game->test_resources.programs[DEFAULT_PROGRAM].handle; + struct gpu_program *current_program = NULL; + + struct gpu_program *terrain_program = + &game->test_resources.programs[TERRAIN_PROGRAM]; + + struct gpu_program *default_program = + &game->test_resources.programs[DEFAULT_PROGRAM]; for (size_t i = 0; i < ARRAY_SIZE(entities); ++i) { struct entity *entity = entities[i]; @@ -265,10 +270,8 @@ void render (struct game *game, struct render_config *config) { continue; // TODO this is a bit wonky, refactor this - if (i == 0) - glUseProgram(terrain_program); - else if (i == 1) - glUseProgram(default_program); + current_program = i == 0 ? terrain_program : default_program; + glUseProgram(current_program->handle); check_gl(); mat4_inverse(camera, view); @@ -288,17 +291,14 @@ void render (struct game *game, struct render_config *config) { camera[M_X], camera[M_Y], camera[M_Z]); - printf("%d depth ? %d\n", (int)i, config->is_depth_pass); glUniform1i(res->uniforms.fog_on, res->fog_on); glUniform1i(res->uniforms.diffuse_on, res->diffuse_on); glUniform3f(res->uniforms.light_dir, light[0], light[1], light[2]); glUniform1f(res->uniforms.light_intensity, res->light_intensity); check_gl(); - printf("light_intensity uniform %d\n", res->uniforms.light_intensity); /* glUniform1f(res->uniforms.time, res->time); */ check_gl(); - printf("sky_intensity uniform %d\n", res->uniforms.sky_intensity); glUniform1f(res->uniforms.sky_intensity, sky_intensity); check_gl(); glUniform3f(res->uniforms.sun_color, @@ -322,21 +322,8 @@ void render (struct game *game, struct render_config *config) { recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); check_gl(); - if (i != 0) { - render_geometry(&entity->model.geom, &res->attributes); - check_gl(); - } - else { - glPatchParameteri(GL_PATCH_VERTICES, 3); - check_gl(); - bind_geometry(&entity->model.geom, &res->attributes); - check_gl(); - glDrawElements(GL_PATCHES, - entity->model.geom.num_indices, - GL_UNSIGNED_INT, 0); - check_gl(); - } - + render_geometry(&entity->model.geom, &res->attributes, current_program); + check_gl(); } if (config->draw_ui) diff --git a/src/shader.c b/src/shader.c @@ -18,6 +18,17 @@ static int file_name_lens[MAX_SHADER_INCLUDES]; static char *line_buff[MAX_LINES]; static u32 line_lens[MAX_LINES]; +static char *cached_file_contents(const char *filename) { + size_t len; + for (int i = 0; i < file_buf_count; i++) { + if (memcmp(file_names[i], filename, file_name_lens[i]) == 0) { + return file_buffers[i]; + } + } + + return file_contents(filename, &len); +} + static char *strsep(char **stringp, const char *delim) { if (*stringp == NULL) { return NULL; } char *token_start = *stringp; @@ -27,13 +38,14 @@ static char *strsep(char **stringp, const char *delim) { return token_start; } -static char **resolve_imports(char *contents, int *nlines) { +static char **resolve_imports(char *contents, int *nlines, int level) { char *line; - size_t file_len; + int nline = 0; char *resolved_contents; - static char fname_buf[32]; + char fname_buf[32] = {0}; while ((line = strsep(&contents, "\n"))) { + nline++; int line_len = contents - line; int size = sizeof("#include"); if (memcmp(line, "#include ", size) == 0) { @@ -42,11 +54,15 @@ static char **resolve_imports(char *contents, int *nlines) { snprintf(fname_buf, 32, SHADER("%.*s"), file_name_len, filename); file_name_lens[file_buf_count] = file_name_len; file_names[file_buf_count] = filename; - /* printf("got include %s\n", fname_buf); */ + + /* printf("got include %.*s at line %d level %d ind %d\n", */ + /* file_name_len, filename, nline, level, file_buf_count); */ + // TODO (perf): cache file contents based on filename - resolved_contents = file_contents(fname_buf, &file_len); - file_buffers[file_buf_count++] = resolved_contents; - resolve_imports(resolved_contents, nlines); + resolved_contents = cached_file_contents(fname_buf); + file_buffers[file_buf_count] = resolved_contents; + file_buf_count++; + resolve_imports(resolved_contents, nlines, level + 1); } else { line_buff[*nlines] = line; @@ -59,15 +75,28 @@ static char **resolve_imports(char *contents, int *nlines) { return line_buff; } + +struct shader *get_program_shader(struct gpu_program *program, GLenum type) { + struct shader *shader; + for (int i = 0; i < program->n_shaders; i++) { + shader = &program->shaders[i]; + if (shader->type == type) + return shader; + } + + return NULL; +} + + int make_shader(GLenum type, const char *filename, struct shader *shader) { size_t length; int nlines = 0; - static char fname_buf[32]; GLchar *source = (GLchar *)file_contents(filename, &length); if (!source) return 0; - char **lines = resolve_imports(source, &nlines); + assert(file_buf_count == 0); + char **lines = resolve_imports(source, &nlines, 0); GLint shader_ok; @@ -79,20 +108,21 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) { glShaderSource(shader->handle, nlines, (const char**)lines, (const int*)line_lens); - free(source); - // shader dependency stuff for (int i = 0; i < file_buf_count; ++i) { assert(i < MAX_SHADER_INCLUDES); char *p = shader->includes[shader->n_includes]; int name_len = file_name_lens[i]; - assert(name_len < MAX_INCLUDE_FNAME_LEN); + /* printf("%.*s name len %d\n", name_len, file_names[i], name_len); */ snprintf(p, MAX_INCLUDE_FNAME_LEN, SHADER("%.*s"), name_len, file_names[i]); + assert(name_len < MAX_INCLUDE_FNAME_LEN); shader->include_mtimes[shader->n_includes] = file_mtime(p); - /* printf("including %s as dep of %s\n", p, name_len, shader->filename); */ + /* printf("'%s' included in '%s'\n", p, shader->filename); */ shader->n_includes++; free(file_buffers[i]); } + free(source); + file_buf_count = 0; glCompileShader(shader->handle); @@ -116,39 +146,33 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) { #ifdef DEBUG int reload_program(struct gpu_program *program) { - struct shader vert, frag; - struct shader *pvert, *pfrag; - time_t frag_mtime, vert_mtime; int ok; int n_shaders = program->n_shaders; + struct gpu_program new_program; struct shader new_shaders[n_shaders]; struct shader *new_shaders_p[n_shaders]; int changes[n_shaders]; for (int i = 0; i < n_shaders; i++) { - new_shaders_p[i] = &new_shaders[i]; changes[i] = 0; struct shader *shader = &program->shaders[i]; - - if (!shader) - continue; + new_shaders_p[i] = shader; time_t mtime = file_mtime(shader->filename); int changed = mtime != shader->load_mtime; - for (int j = 0; i < shader->n_includes; ++j) { + for (int j = 0; j < shader->n_includes; ++j) { time_t include_mtime = shader->include_mtimes[j]; time_t new_mtime = file_mtime(shader->includes[j]); - changed |= mtime != new_mtime; + changed |= include_mtime != new_mtime; } changes[i] = changed; if (changed) { - GLuint old_handle = shader->handle; - + /* printf("making shader %s\n", shader->filename); */ ok = make_shader(shader->type, shader->filename, &new_shaders[i]); if (!ok) { // clean up all the new shaders we've created so far @@ -156,6 +180,7 @@ int reload_program(struct gpu_program *program) { glDeleteShader(new_shaders[k].handle); return 0; } + new_shaders_p[i] = &new_shaders[i]; } } @@ -163,18 +188,21 @@ int reload_program(struct gpu_program *program) { for (int i = 0; i < n_shaders; i++) any_changes |= changes[i]; - if (!any_changes) + if (!any_changes) { return 2; - - // delete old shaders - for (int i = 0; i < n_shaders; i++) { - glDeleteShader(program->shaders[i].handle); } - glDeleteProgram(program->handle); + ok = make_program_from_shaders(new_shaders_p, n_shaders, &new_program); + + if (!ok) { + for (int i = 0; i < n_shaders; i++) { + glDeleteShader(program->shaders[i].handle); + } + return 0; + } - // TODO: cleanup failed make_program? - return make_program_from_shaders(new_shaders_p, n_shaders, program); + *program = new_program; + return 1; } #endif @@ -194,12 +222,18 @@ make_program_from_shaders(struct shader **shaders, int n_shaders, struct gpu_pro // TODO: relax these constraints program->handle = glCreateProgram(); + program->n_shaders = n_shaders; assert(n_shaders <= MAX_SHADERS); for (int i = 0; i < n_shaders; i++) { - program->shaders[i] = *shaders[i]; - struct shader *shader = &program->shaders[i]; - glAttachShader(program->handle, shaders[i]->handle); + struct shader *shader = shaders[i]; + program->shaders[i] = *shader; + /* printf("attaching shader %s\n", shader->filename); */ + /* for (int j = 0; j < shader->n_includes; ++j) { */ + /* printf("attaching shader %s dep %s \n", shader->filename, */ + /* shader->includes[j]); */ + /* } */ + glAttachShader(program->handle, shader->handle); } glLinkProgram(program->handle); diff --git a/src/shader.h b/src/shader.h @@ -6,8 +6,8 @@ #define SHADER(f) "etc/shaders/" f -#define MAX_SHADER_INCLUDES 8 -#define MAX_INCLUDE_FNAME_LEN 48 +#define MAX_SHADER_INCLUDES 16 +#define MAX_INCLUDE_FNAME_LEN 64 #define MAX_SHADERS 5 struct shader { @@ -36,6 +36,8 @@ int make_program_from_shaders(struct shader **shaders, int n_shaders, struct gpu_program *program); +struct shader *get_program_shader(struct gpu_program *program, GLenum type); + int make_program(struct shader *vertex, struct shader *fragment, struct gpu_program *program); diff --git a/src/ui.c b/src/ui.c @@ -68,7 +68,7 @@ void render_ui(struct ui *ui, float *view) { check_gl(); // render quad - render_geometry(&ui->quad, &ui->attrs); + render_geometry(&ui->quad, &ui->attrs, ui->shader); check_gl(); } diff --git a/src/update.c b/src/update.c @@ -39,10 +39,10 @@ static void movement(struct game *game, struct node *node, float speed_mult) { if (game->input.keystates[SDL_SCANCODE_S]) node_forward(node, V3(0,-amt,0)); - if (game->input.keystates[SDL_SCANCODE_R]) + if (game->input.keystates[SDL_SCANCODE_K]) node_translate(node, V3(0, 0,amt)); - if (game->input.keystates[SDL_SCANCODE_F]) + if (game->input.keystates[SDL_SCANCODE_J]) node_translate(node, V3(0, 0,-amt)); if (game->input.keystates[SDL_SCANCODE_E]) @@ -188,6 +188,7 @@ static void player_movement(struct game *game) { #ifdef DEBUG static int try_reload_shaders(struct resources *res) { int ret; + static int wut = 0; for (int i = 0; i < NUM_PROGRAMS; ++i) { struct gpu_program *program = &res->programs[i]; ret = reload_program(program);