polyadvent

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

commit b8699114390f7d006277084c73f04e9a39d3d87e
parent 86dcd139cfc222aafa710dab3d941df5fa481301
Author: William Casarin <jb55@jb55.com>
Date:   Thu,  1 Nov 2018 21:40:00 -0700

geometry shader done

but probably won't go with it.

going to try a tessellation shader

Diffstat:
Metc/shaders/lighting.glsl | 14+++++++-------
Metc/shaders/standard_vtxos.glsl | 10+++++-----
Detc/shaders/terrain.glsl | 51---------------------------------------------------
Metc/shaders/test.f.glsl | 38++++++++++++++++++++------------------
Metc/shaders/ui.f.glsl | 2+-
Metc/shaders/ui.v.glsl | 2+-
Metc/shaders/vertex-color.glsl | 16+++++-----------
Msrc/game.c | 2+-
Msrc/render.c | 21+++++++++++++--------
Msrc/shader.c | 128+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/shader.h | 12+++++++++---
Msrc/terrain.c | 2++
Msrc/update.c | 8++------
13 files changed, 126 insertions(+), 180 deletions(-)

diff --git a/etc/shaders/lighting.glsl b/etc/shaders/lighting.glsl @@ -1,6 +1,6 @@ -#include noise.glsl +//#include noise.glsl // float clouds(vec3 position) { @@ -19,16 +19,16 @@ vec3 gamma_correct(vec3 color) { return pow(color, vec3(1.0/2.2)); } -vec3 standard_light(vec3 color, vec3 position) { - vec4 v4_normal = vec4(v_normal , 1); +vec3 standard_light(vec3 color, vec3 position, vec3 normal) { + vec4 v4_normal = vec4(normal, 1); vec4 trans_normal = normal_matrix * v4_normal; - vec3 light_dir = vec3() + // vec3 light_dir = vec3() const float pi = 3.14159265; const float shiny = 12.0; const float exposure = 0.2; const float ambient_str = 0.2; - float spec_str = 0.4 * light_intensity; + float spec_str = 0.8 * light_intensity; // float light_intensity = light_intensity * 0.01; @@ -56,12 +56,12 @@ vec3 standard_light(vec3 color, vec3 position) { if (blinn) { const float energy_conservation = ( 8.0 + shiny ) / ( 8.0 * pi ); vec3 halfway_dir = normalize(light_dir + view_dir); // blinn-phong - spec = energy_conservation * pow(max(dot(v_normal, halfway_dir), 0.0), shiny); + spec = energy_conservation * pow(max(dot(normal, halfway_dir), 0.0), shiny); } else { const float energy_conservation = ( 2.0 + shiny ) / ( 2.0 * pi ); - vec3 reflect_dir = reflect(-light_dir, v_normal); // phong + vec3 reflect_dir = reflect(-light_dir, normal); // phong spec = energy_conservation * pow(max(dot(view_dir, reflect_dir), 0.0), shiny); } // spec += pow(max(dot(view_dir, reflect_dir), 0.0), 16.0) * 0.5; diff --git a/etc/shaders/standard_vtxos.glsl b/etc/shaders/standard_vtxos.glsl @@ -1,7 +1,7 @@ vec4 v4_pos = vec4(position, 1.0); gl_Position = mvp * v4_pos; -v_normal = normal; -v_color_smooth = v_color = color; -shadow_coord = depth_mvp * v4_pos; -v_position = position; -v_frag_pos = (world * v4_pos).xyz; +vertex.normal = normal; +vertex.color = vertex.color_smooth = color; +vertex.shadow_coord = depth_mvp * v4_pos; +vertex.position = position; +vertex.frag_pos = (world * v4_pos).xyz; diff --git a/etc/shaders/terrain.glsl b/etc/shaders/terrain.glsl @@ -1,51 +0,0 @@ -#version 300 es - -precision mediump float; - -in vec3 position; -in vec3 normal; - -#include uniforms.glsl - -flat out float v_light; -flat out vec3 v_color; -out vec3 v_color_smooth; - -out vec3 v_normal; -out vec3 v_ray; -out vec3 v_position; -out vec3 v_frag_pos; -out vec4 shadow_coord; - -const int nlands = 6; - -#include lighting.glsl - - -const vec4 land[nlands] = vec4[]( - vec4(0.0, 0.5, 0.79, 0.0), // 0 - water - vec4(0.9176, 0.8156, 0.6588, 1.0), // 1 - sand - vec4(0.7, 0.7, 0.156, 2.0), // 2 - grass - vec4(0.4627, 0.3333, 0.1686, 20.0), // 3 - dirt - vec4(0.5, 0.5, 0.5, 80.0), // 4 - stone - vec4(1.0, 1.0, 1.0, 380.0) // 5 - snow -); - - -void main() -{ - vec3 color = land[0].xyz; - for (int i = 0; i < nlands-1; i++) { - color = - mix(color, - land[i+1].xyz, - smoothstep(land[i].w, land[i+1].w, position.z)); - } - - // vec3 color = vec3(position.z*0.05, position.z*0.0095, position.z*0.0001) * 0.5; - - - // v_color = vec3(position.z, position.z, position.z) * 0.005; - -#include standard_vtxos.glsl -} diff --git a/etc/shaders/test.f.glsl b/etc/shaders/test.f.glsl @@ -1,33 +1,37 @@ -#version 300 es +#include profile precision mediump float; -flat in vec3 v_color; -in vec3 v_color_smooth; -in vec3 v_ray; -in vec3 v_normal; -in vec3 v_position; -in vec4 shadow_coord; -in vec3 v_frag_pos; out vec4 frag_color; #include uniforms.glsl +in f_data { +#include shadervars.glsl +} vertex; + +// in flat vec3 v_color; +// in vec3 v_color_smooth; +// in vec3 v_ray; +// in vec3 v_normal; +// in vec3 v_position; +// in vec4 v_shadow_coord; +// in vec3 v_frag_pos; + uniform sampler2D shadow_map; #include lighting.glsl #include fog.glsl void main() { - const float smoothness = 0.0; float visibility = 1.0; - vec4 shadow_sample = texture(shadow_map, shadow_coord.xy); - vec3 v_ray = camera_position - v_frag_pos; + vec4 shadow_sample = texture(shadow_map, vertex.shadow_coord.xy); + vec3 v_ray = camera_position - vertex.frag_pos; - // vec3 color = v_color * (1.0-smoothness) - // + v_color_smooth * smoothness; - vec3 color = standard_light(v_color, v_position); + // vec3 color = vertex.color * (1.0-smoothness) + // + 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); @@ -35,15 +39,13 @@ void main() { color = fog; } - if (light_dir.z > 0.0 && shadow_sample.z < shadow_coord.z ) { + 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)); visibility = clamp(0.2 * factor, 0.5, 1.0); } color = color * visibility; - // float dist = length(camera_position - v_position); + // float dist = length(camera_position - vertex.position); - // fragmentColor = vec4(color + diffuse, 1.0); frag_color = vec4(color, 1.0); - // fragmentColor = vec4(color * 0.0001 + length(v_ray) * 0.0001, 1.0); } diff --git a/etc/shaders/ui.f.glsl b/etc/shaders/ui.f.glsl @@ -1,4 +1,4 @@ -#version 300 es +#include profile precision mediump float; diff --git a/etc/shaders/ui.v.glsl b/etc/shaders/ui.v.glsl @@ -1,4 +1,4 @@ -#version 300 es +#include profile in vec3 position; in vec3 color; diff --git a/etc/shaders/vertex-color.glsl b/etc/shaders/vertex-color.glsl @@ -1,22 +1,16 @@ - -#version 300 es - +#include profile precision mediump float; - in vec3 position; in vec3 normal; in vec3 color; #include uniforms.glsl -flat out float v_light; +out f_data { +#include shadervars.glsl +} vertex; + flat out vec3 v_color; -out vec3 v_color_smooth; -out vec3 v_normal; -out vec3 v_position; -out vec3 v_ray; -out vec3 v_frag_pos; -out vec4 shadow_coord; void main() { diff --git a/src/game.c b/src/game.c @@ -54,7 +54,7 @@ void game_init(struct game *game, int width, int height) { .scale = 1.0 }; - static const int shadowmap_scale = 100.0; + static const int shadowmap_scale = 10.0; // default ortho screenspace projection mat4_ortho(-shadowmap_scale, // left diff --git a/src/render.c b/src/render.c @@ -62,7 +62,7 @@ static const float bias_matrix[] = { void init_gl(struct resources *resources, int width, int height) { - struct shader vertex, terrain_vertex, fragment, fragment_smooth; + struct shader vertex, terrain_vertex, terrain_geom, fragment, fragment_smooth; float tmp_matrix[16]; int ok = 0; @@ -74,9 +74,14 @@ init_gl(struct resources *resources, int width, int height) { ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), &vertex); assert(ok && "vertex-color shader"); - ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.glsl"), &terrain_vertex); + ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"), + &terrain_vertex); assert(ok && "terrain vertex shader"); + ok = make_shader(GL_GEOMETRY_SHADER, SHADER("terrain.g.glsl"), + &terrain_geom); + assert(ok && "terrain geometry shader"); + ok = make_shader(GL_FRAGMENT_SHADER, SHADER("test.f.glsl"), &fragment); assert(ok && "default fragment shader"); @@ -88,8 +93,8 @@ init_gl(struct resources *resources, int width, int height) { resources->proj_persp); // Shader program - ok = make_program(&terrain_vertex, &fragment, - &resources->programs[TERRAIN_PROGRAM]); + struct shader *shaders[] = { &terrain_vertex, &fragment, &terrain_geom }; + ok = make_program_from_shaders(shaders, 3, &resources->programs[TERRAIN_PROGRAM]); assert(ok && "terrain program"); check_gl(); @@ -195,7 +200,7 @@ void render (struct game *game, struct render_config *config) { glClearColor( gtmp[0], gtmp[1], gtmp[2], 1.0 ); //clear background screen to black /* glClearColor( 0.5294f * adjust, 0.8078f * adjust, 0.9216f * adjust, 1.0f ); //clear background screen to black */ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glEnable(GL_CULL_FACE); + /* glEnable(GL_CULL_FACE); */ check_gl(); @@ -239,11 +244,11 @@ void render (struct game *game, struct render_config *config) { if (config->is_depth_pass) { mat4_multiply(bias_matrix, view_proj, config->depth_mvp); - glCullFace(GL_FRONT); + glCullFace(GL_FRONT); } else { glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, config->depth_mvp); - glCullFace(GL_BACK); + glCullFace(GL_BACK); } glUniform3f(res->uniforms.camera_position, @@ -261,7 +266,7 @@ void render (struct game *game, struct render_config *config) { res->sun_color[0], res->sun_color[1], res->sun_color[2]); - + mat4_multiply(view_proj, entity->node.mat, mvp); mat4_copy(entity->node.mat, model_view); diff --git a/src/shader.c b/src/shader.c @@ -112,6 +112,7 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) { return 1; } +#define N_SHADERS 3 #ifdef DEBUG int reload_program(struct gpu_program *program) { @@ -120,96 +121,87 @@ int reload_program(struct gpu_program *program) { time_t frag_mtime, vert_mtime; int ok; - vert_mtime = file_mtime(program->vertex.filename); - frag_mtime = file_mtime(program->fragment.filename); + int n_shaders = program->n_shaders; + struct shader new_shaders[n_shaders]; + struct shader *new_shaders_p[n_shaders]; - int vert_changed = - vert_mtime != program->vertex.load_mtime; + int changes[n_shaders]; - int frag_changed = - frag_mtime != program->fragment.load_mtime; + for (int i = 0; i < n_shaders; i++) { + new_shaders_p[i] = &new_shaders[i]; + changes[i] = 0; + struct shader *shader = &program->shaders[i]; - for (int i = 0; i < program->vertex.n_includes; ++i) { - time_t include_mtime = program->vertex.include_mtimes[i]; - time_t new_mtime = file_mtime(program->vertex.includes[i]); - vert_changed |= include_mtime != new_mtime; - } - - for (int i = 0; i < program->fragment.n_includes; ++i) { - time_t include_mtime = program->fragment.include_mtimes[i]; - frag_changed |= include_mtime != file_mtime(program->fragment.includes[i]); - } - - if (!vert_changed && !frag_changed) - return 2; - - // recompile vertex shader - if (vert_changed) { - glDeleteShader(program->vertex.handle); - - ok = - make_shader(GL_VERTEX_SHADER, - program->vertex.filename, - &vert); + if (!shader) + continue; - if (!ok) - return 0; - } - - // recompile fragment shader - if (frag_changed) { - glDeleteShader(program->fragment.handle); + time_t mtime = file_mtime(shader->filename); + int changed = mtime != shader->load_mtime; - ok = - make_shader(GL_FRAGMENT_SHADER, - program->fragment.filename, - &frag); + for (int j = 0; i < 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; + } + + changes[i] = changed; + + if (changed) { + GLuint old_handle = shader->handle; + + ok = make_shader(shader->type, shader->filename, &new_shaders[i]); + if (!ok) { + // clean up all the new shaders we've created so far + for (int k = 0; k < i; k++) + glDeleteShader(new_shaders[k].handle); + return 0; + } + } + } - if (!ok) - return 0; - } + int any_changes = 0; + for (int i = 0; i < n_shaders; i++) + any_changes |= changes[i]; - if (vert_changed) { - glDeleteShader(program->vertex.handle); - pvert = &vert; - vert.load_mtime = vert_mtime; - } - else - pvert = &program->vertex; + if (!any_changes) + return 2; - if (frag_changed) { - glDeleteShader(program->fragment.handle); - pfrag = &frag; - frag.load_mtime = frag_mtime; - } - else - pfrag = &program->fragment; + // delete old shaders + for (int i = 0; i < n_shaders; i++) { + glDeleteShader(program->shaders[i].handle); + } glDeleteProgram(program->handle); - make_program(pvert, pfrag, program); - - return 1; + // TODO: cleanup failed make_program? + return make_program_from_shaders(new_shaders_p, n_shaders, program); } #endif int -make_program(struct shader *vertex, struct shader *fragment, - struct gpu_program *program) +make_program(struct shader *vertex, + struct shader *fragment, + struct gpu_program *program) +{ + struct shader *shaders[] = { vertex, fragment }; + return make_program_from_shaders(shaders, 2, program); +} + +int +make_program_from_shaders(struct shader **shaders, int n_shaders, struct gpu_program *program) { GLint program_ok; // TODO: relax these constraints - assert(vertex); - assert(fragment); - program->handle = glCreateProgram(); - program->fragment = *fragment; - program->vertex = *vertex; + 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, vertex->handle); - glAttachShader(program->handle, fragment->handle); + glAttachShader(program->handle, shader->handle); + } glLinkProgram(program->handle); diff --git a/src/shader.h b/src/shader.h @@ -7,7 +7,8 @@ #define SHADER(f) "etc/shaders/" f #define MAX_SHADER_INCLUDES 8 -#define MAX_INCLUDE_FNAME_LEN 32 +#define MAX_INCLUDE_FNAME_LEN 48 +#define MAX_SHADERS 5 struct shader { GLenum type; @@ -20,16 +21,21 @@ struct shader { }; struct gpu_program { - struct shader vertex; - struct shader fragment; + struct shader shaders[MAX_SHADERS]; + int n_shaders; GLuint handle; }; +#define NO_GEOM_SHADER NULL int reload_program(struct gpu_program *program); int make_shader(GLenum type, const char *filename, struct shader *shader); +int make_program_from_shaders(struct shader **shaders, + int n_shaders, + struct gpu_program *program); + int make_program(struct shader *vertex, struct shader *fragment, struct gpu_program *program); diff --git a/src/terrain.c b/src/terrain.c @@ -143,8 +143,10 @@ terrain_create(struct terrain *terrain) { /* vec3_subtract(v[1], c, tmp1); */ /* vec3_subtract(v[2], c, tmp2); */ + // standard normals vec3_subtract(v[1], v[0], tmp1); vec3_subtract(v[2], v[0], tmp2); + vec3_cross(tmp1, tmp2, tmp2); vec3_normalize(tmp2, tmp2); diff --git a/src/update.c b/src/update.c @@ -194,13 +194,9 @@ static int try_reload_shaders(struct resources *res) { if (ret == 2) {} else if (ret == 1) - printf("reload %s + %s success.\n", - program->vertex.filename, - program->fragment.filename); + printf("reload %s success.\n", program->shaders[0].filename); else - printf("reload %s + %s failed.\n", - program->vertex.filename, - program->fragment.filename); + printf("reload %s failed.\n", program->shaders[0].filename); // failure ok, clear any errors glGetError();