commit 534606327d29470da8f36a285081e6dcad721f8c
parent 4b1cce3d38e145ca6e13e7b16b8e4b308f13ebf6
Author: William Casarin <jb55@jb55.com>
Date: Mon, 29 Oct 2018 17:00:47 -0700
dependency tracking on includes for reload_shader
Diffstat:
12 files changed, 114 insertions(+), 44 deletions(-)
diff --git a/etc/shaders/lighting.glsl b/etc/shaders/lighting.glsl
@@ -11,6 +11,23 @@ vec3 standard_light(vec3 color) {
return color * costheta;
}
+
+const vec3 spherical_harmonics[4] = vec3[](
+ vec3( 0.754554516862612, 0.748542953903366, 0.790921515418539 ),
+ vec3( -0.083856548007422, 0.092533500963210, 0.322764661032516 ),
+ vec3( 0.308152705331738, 0.366796330467391, 0.466698181299906 ),
+ vec3( -0.188884931542396, -0.277402551592231, -0.377844212327557 )
+);
+
+vec3 irradiance_spherical_harmonics(const vec3 n) {
+ return max(
+ spherical_harmonics[0]
+ + spherical_harmonics[1] * n.y
+ + spherical_harmonics[2] * n.z
+ + spherical_harmonics[3] * n.x
+ , 0.0);
+}
+
vec3 gamma_correct(vec3 color) {
return pow(color, vec3(1.0/2.2));
}
diff --git a/etc/shaders/terrain.glsl b/etc/shaders/terrain.glsl
@@ -17,6 +17,7 @@ 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
@@ -33,8 +34,7 @@ void main()
shadow_coord = depth_mvp * v4_pos;
vec3 color = land[0].xyz;
-
- for (int i = 0; i < nlands-1; i++) {
+ for (int i = 0; i < nlands-1; i++) {
color =
mix(color,
land[i+1].xyz,
diff --git a/etc/shaders/test.f.glsl b/etc/shaders/test.f.glsl
@@ -49,6 +49,7 @@ void main() {
color = frag;
float shadow_map_z = texture(shadow_map, shadow_coord.xy).z;
+
if (light_dir.z > 0.0 && shadow_map_z < 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);
diff --git a/etc/shaders/ui.f.glsl b/etc/shaders/ui.f.glsl
@@ -11,5 +11,5 @@ uniform sampler2D screen_texture;
void main() {
// fragmentColor = vec4(color + diffuse, 1.0);
- fragmentColor = texture(screen_texture, v_tex_coords) + vec4(v_color, 1.0) * 0.000001;
+ fragmentColor = texture(screen_texture, v_tex_coords) + vec4(v_color, 0.0) * 0.0001;
}
diff --git a/src/game.c b/src/game.c
@@ -67,7 +67,8 @@ void game_init(struct game *game, int width, int height) {
res->proj_ortho
);
- create_ui(&game->ui, width, height);
+ create_ui(&game->ui, width, height, &res->programs[UI_PROGRAM]);
+
check_gl();
terrain_init(terrain);
diff --git a/src/game.h b/src/game.h
@@ -14,6 +14,15 @@
#define PLAYER_HEIGHT 1.73
+#define MAX_PROGRAMS 12
+
+enum program_type {
+ DEFAULT_PROGRAM,
+ TERRAIN_PROGRAM,
+ UI_PROGRAM,
+ NUM_PROGRAMS,
+};
+
/*
* Global data used by our render callback:
* NOTE: just for testing right now
@@ -22,10 +31,7 @@ struct resources {
struct vbo vertex_buffer, element_buffer, normal_buffer;
struct fbo shadow_buffer;
- struct gpu_program program;
- struct gpu_program smooth_program;
- struct gpu_program terrain_program;
- struct gpu_program ui_program;
+ struct gpu_program programs[NUM_PROGRAMS];
struct uniforms {
GLint camera_position;
diff --git a/src/render.c b/src/render.c
@@ -81,17 +81,19 @@ init_gl(struct resources *resources, int width, int height) {
resources->proj_persp);
// Shader program
- ok = make_program(&terrain_vertex, &fragment, &resources->terrain_program);
+ ok = make_program(&terrain_vertex, &fragment,
+ &resources->programs[TERRAIN_PROGRAM]);
+
assert(ok && "terrain program");
check_gl();
- ok = make_program(&vertex, &fragment, &resources->program);
+ ok = make_program(&vertex, &fragment, &resources->programs[DEFAULT_PROGRAM]);
assert(ok && "vertex-color program");
check_gl();
GLuint programs[] =
- { resources->terrain_program.handle
- , resources->program.handle
+ { resources->programs[TERRAIN_PROGRAM].handle
+ , resources->programs[DEFAULT_PROGRAM].handle
};
// uniforms shared between all shaders
@@ -139,7 +141,8 @@ init_gl(struct resources *resources, int width, int height) {
// TODO: auto-generate these somehow?
resources->attributes.color =
- (gpu_addr)glGetAttribLocation(resources->program.handle, "color");
+ (gpu_addr)glGetAttribLocation(resources->programs[DEFAULT_PROGRAM]
+ .handle, "color");
check_gl();
}
@@ -185,6 +188,8 @@ void render (struct game *game, struct render_config *config) {
};
int is_shadow = config->draw_ui == 0;
+ int terrain_program = game->test_resources.programs[TERRAIN_PROGRAM].handle;
+ int default_program = game->test_resources.programs[DEFAULT_PROGRAM].handle;
for (size_t i = 0; i < ARRAY_SIZE(entities); ++i) {
struct entity *entity = entities[i];
@@ -192,9 +197,9 @@ void render (struct game *game, struct render_config *config) {
continue;
// TODO this is a bit wonky, refactor this
if (i == 0)
- glUseProgram(game->test_resources.terrain_program.handle);
+ glUseProgram(terrain_program);
else if (i == 1)
- glUseProgram(game->test_resources.program.handle);
+ glUseProgram(default_program);
check_gl();
mat4_inverse(camera, view);
@@ -242,8 +247,8 @@ void render (struct game *game, struct render_config *config) {
check_gl();
}
- /* if (config->draw_ui) */
- /* render_ui(&game->ui, view); */
+ if (config->draw_ui)
+ render_ui(&game->ui, view);
//player
// y tho
diff --git a/src/shader.c b/src/shader.c
@@ -12,7 +12,9 @@
#define MAX_LINES 4096
static int file_buf_count = 0;
-static char *file_buffers[12];
+static char *file_buffers[MAX_SHADER_INCLUDES];
+static char *file_names[MAX_SHADER_INCLUDES];
+static int file_name_lens[MAX_SHADER_INCLUDES];
static char *line_buff[MAX_LINES];
static u32 line_lens[MAX_LINES];
@@ -36,8 +38,12 @@ static char **resolve_imports(char *contents, int *nlines) {
int size = sizeof("#include");
if (memcmp(line, "#include ", size) == 0) {
char *filename = line + size;
- snprintf(fname_buf, 32, SHADER("%.*s"), line_len-size-1, filename);
+ int file_name_len = line_len - size - 1;
+ 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); */
+ // 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);
@@ -55,6 +61,7 @@ static char **resolve_imports(char *contents, int *nlines) {
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;
@@ -63,6 +70,7 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) {
GLint shader_ok;
+ shader->n_includes = 0;
shader->filename = filename;
shader->type = type;
shader->handle = glCreateShader(type);
@@ -71,8 +79,19 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) {
(const int*)line_lens);
free(source);
- for (int i = 0; i < file_buf_count; ++i)
+
+ // 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);
+ snprintf(p, MAX_INCLUDE_FNAME_LEN, SHADER("%.*s"), name_len, file_names[i]);
+ shader->include_mtimes[shader->n_includes] = file_mtime(p);
+ /* printf("including %s as dep of %s\n", p, name_len, shader->filename); */
+ shader->n_includes++;
free(file_buffers[i]);
+ }
file_buf_count = 0;
glCompileShader(shader->handle);
@@ -86,10 +105,8 @@ int make_shader(GLenum type, const char *filename, struct shader *shader) {
return 0;
}
-#ifdef DEBUG
shader->load_mtime =
file_mtime(shader->filename);
-#endif
return 1;
}
@@ -111,6 +128,17 @@ int reload_program(struct gpu_program *program) {
int frag_changed =
frag_mtime != program->fragment.load_mtime;
+ 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;
@@ -174,8 +202,7 @@ make_program(struct shader *vertex, struct shader *fragment,
assert(vertex);
assert(fragment);
- program->handle =
- glCreateProgram();
+ program->handle = glCreateProgram();
program->fragment = *fragment;
program->vertex = *vertex;
diff --git a/src/shader.h b/src/shader.h
@@ -6,13 +6,17 @@
#define SHADER(f) "etc/shaders/" f
+#define MAX_SHADER_INCLUDES 8
+#define MAX_INCLUDE_FNAME_LEN 32
+
struct shader {
GLenum type;
GLuint handle;
+ int n_includes;
const char *filename;
-#ifdef DEBUG
+ char includes[MAX_SHADER_INCLUDES][MAX_INCLUDE_FNAME_LEN];
+ time_t include_mtimes[MAX_SHADER_INCLUDES];
time_t load_mtime;
-#endif
};
struct gpu_program {
@@ -22,9 +26,7 @@ struct gpu_program {
};
-#ifdef DEBUG
int reload_program(struct gpu_program *program);
-#endif
int make_shader(GLenum type, const char *filename, struct shader *shader);
diff --git a/src/ui.c b/src/ui.c
@@ -50,7 +50,7 @@ static void create_quad(struct geometry *geom)
void render_ui(struct ui *ui, float *view) {
static float mvp[MAT4_ELEMS];
glDisable(GL_DEPTH_TEST);
- glUseProgram(ui->shader.handle);
+ glUseProgram(ui->shader->handle);
check_gl();
float uipos[2] = {0.01, 0.01};
@@ -85,11 +85,12 @@ void resize_ui(struct ui *ui, int width, int height) {
}
-void create_ui(struct ui *ui, int width, int height) {
+void create_ui(struct ui *ui, int width, int height, struct gpu_program *shader) {
struct shader vertex;
struct shader fragment;
int ok = 0;
+ ui->shader = shader;
create_quad(&ui->quad);
check_gl();
@@ -99,10 +100,10 @@ void create_ui(struct ui *ui, int width, int height) {
ok = make_shader(GL_FRAGMENT_SHADER, SHADER("ui.f.glsl"), &fragment);
assert(ok && "ui fragment shader");
- ok = make_program(&vertex, &fragment, &ui->shader);
+ ok = make_program(&vertex, &fragment, ui->shader);
assert(ok && "ui program");
- GLuint program = ui->shader.handle;
+ GLuint program = ui->shader->handle;
ui->uniforms.mvp = glGetUniformLocation(program, "mvp");
ui->uniforms.uipos = glGetUniformLocation(program, "uipos");
diff --git a/src/ui.h b/src/ui.h
@@ -7,7 +7,7 @@
#include "geometry.h"
struct ui {
- struct gpu_program shader;
+ struct gpu_program *shader;
struct geometry quad;
struct attributes attrs;
@@ -21,7 +21,9 @@ struct ui {
float ortho[MAT4_ELEMS];
};
-void create_ui(struct ui *ui, int width, int height);
+void create_ui(struct ui *ui, int width, int height,
+ struct gpu_program *);
+
void resize_ui(struct ui *ui, int width, int height);
void render_ui(struct ui *ui, float *camera);
diff --git a/src/update.c b/src/update.c
@@ -183,16 +183,24 @@ static void player_movement(struct game *game) {
#ifdef DEBUG
static int try_reload_shaders(struct resources *res) {
int ret;
- printf("reloading shaders... ");
-
- ret = reload_program(&res->program);
+ for (int i = 0; i < NUM_PROGRAMS; ++i) {
+ struct gpu_program *program = &res->programs[i];
+ ret = reload_program(program);
+
+ if (ret == 2) {}
+ else if (ret == 1)
+ printf("reload %s + %s success.\n",
+ program->vertex.filename,
+ program->fragment.filename);
+ else
+ printf("reload %s + %s failed.\n",
+ program->vertex.filename,
+ program->fragment.filename);
+
+ // failure ok, clear any errors
+ glGetError();
+ }
- if (ret == 2)
- printf("nothing to reload\n");
- else if (ret == 1)
- printf("success.\n");
- else
- printf("failed.\n");
@@ -227,7 +235,7 @@ void resize_fbos(struct game *game, int width, int height) {
// TODO: match based on some real concept of time
static void day_night_cycle(float n, struct resources *res) {
float darkest = 0.3;
- float val = n*100.0;
+ float val = 9950.0;
float roots = vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0));
float intensity = clamp(roots, darkest, 1.0);
float light_pos[3];