polyadvent

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

commit 0a836ee9e2e9afcd5b5d9896c4f37899a85013c6
parent bc3dcbe74ab4c77aff83896addf26e9e4dff2e25
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 10 May 2020 01:29:41 -0700

finally fix shader crashes

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/game.c | 6+-----
Msrc/game.h | 24+-----------------------
Msrc/model.h | 12++++++------
Msrc/render.c | 255++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/shader.c | 13++++++++-----
Msrc/shader.h | 39++++++++++++++++++++++++++++++++++-----
Msrc/skybox.c | 2+-
Msrc/ui.c | 2+-
8 files changed, 167 insertions(+), 186 deletions(-)

diff --git a/src/game.c b/src/game.c @@ -111,20 +111,16 @@ void init_misc(struct game *game, int width, int height) { }; create_ui(&game->ui, width, height, &res->programs[UI_PROGRAM]); - check_gl(); init_terrain(terrain, size); - int seed; /* terrain->samples = load_samples(&seed, &terrain->n_samples); */ terrain->n_samples = 0; create_terrain(terrain, size, game->seed); /* update_terrain(terrain, terrain->cell_size); */ - /* get_entity(&terrain->entity_id)->flags |= ENT_INVISIBLE; */ - create_skybox(&res->skybox, &res->programs[SKYBOX_PROGRAM]); - /* node_translate(&res->skybox.node, V3(-100.0, -100.0, 0.0)); */ + create_skybox(&res->skybox, &res->programs[SKYBOX_PROGRAM]); /* node_translate(&res->skybox.node, V3(-100.0, -100.0, 0.0)); */ /* node_scale(&res->skybox.node, size/4.0); */ mat4_id(mvp); diff --git a/src/game.h b/src/game.h @@ -27,29 +27,7 @@ struct resources { struct vbo vertex_buffer, element_buffer, normal_buffer; struct fbo shadow_buffer; - struct gpu_program programs[NUM_PROGRAMS]; - - struct uniforms { - GLint ambient_str; - GLint camera_position; - GLint depth_mvp; - GLint depth_vp; - GLint diffuse_on; - GLint fog_on; - GLint light_dir; - GLint light_intensity; - GLint model; - GLint model_view; - GLint mvp; - GLint normal_matrix; - GLint sky_intensity; - GLint piece_color; - GLint sun_color; - GLint time; - GLint view_proj; - } uniforms; - - gpu_addr vertex_attrs[MAX_VERTEX_ATTRS]; + struct gpu_program programs[MAX_PROGRAMS]; node_id root_id; entity_id player_id; diff --git a/src/model.h b/src/model.h @@ -18,12 +18,12 @@ typedef struct resource_id model_id; enum program_type { - DEFAULT_PROGRAM, - TERRAIN_PROGRAM, - UI_PROGRAM, - SKYBOX_PROGRAM, - CHESS_PIECE_PROGRAM, - NUM_PROGRAMS, + DEFAULT_PROGRAM, + TERRAIN_PROGRAM, + UI_PROGRAM, + SKYBOX_PROGRAM, + CHESS_PIECE_PROGRAM, + NUM_PROGRAMS, }; diff --git a/src/render.c b/src/render.c @@ -62,8 +62,33 @@ static const float bias_matrix[] = { 0.5, 0.5, 0.5, 1.0 }; -void -init_gl(struct resources *resources, int width, int height) { +static void add_attribute(struct gpu_program *program, + const char *name, + enum vertex_attr attr) +{ + int id = program->vertex_attrs[attr] = + (gpu_addr)glGetAttribLocation(program->handle, name); + /* assert(id != -1); */ + check_gl(); +} + +static void add_uniform(struct gpu_program *program, + const char *name, + enum uniform_id id) +{ + struct uniform *var = &program->uniforms[id]; + var->name = name; + var->id = id; + var->location = glGetUniformLocation(program->handle, var->name); + if (var->location == -1) { + debug("warn: could not find uniform location: %s in program %s\n", + var->name, program->name); + } + /* assert(var->location != -1); */ + check_gl(); +} + +void init_gl(struct resources *resources, int width, int height) { struct shader vertex, terrain_vertex, chess_piece_vertex, terrain_geom, fragment, fragment_smooth; struct shader terrain_teval, terrain_tc; float tmp_matrix[16]; @@ -77,7 +102,8 @@ init_gl(struct resources *resources, int width, int height) { check_gl(); // Shaders - ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), &vertex); + ok = make_shader(GL_VERTEX_SHADER, SHADER("vertex-color.glsl"), + &vertex); rtassert(ok, "vertex-color shader"); ok = make_shader(GL_VERTEX_SHADER, SHADER("terrain.v.glsl"), &terrain_vertex); @@ -102,113 +128,56 @@ init_gl(struct resources *resources, int width, int height) { struct shader *terrain_shaders[] = { &terrain_vertex, &fragment }; - ok = make_program_from_shaders(terrain_shaders, ARRAY_SIZE(terrain_shaders), - &resources->programs[TERRAIN_PROGRAM]); + struct gpu_program *programs = resources->programs; + struct gpu_program *program; + ok = make_program("terrain", &terrain_vertex, &fragment, + &programs[TERRAIN_PROGRAM]); // TODO: replace rtassert with error reporting/handling rtassert(ok, "terrain program"); check_gl(); - ok = make_program(&vertex, &fragment, &resources->programs[DEFAULT_PROGRAM]); + ok = make_program("vertex-color", &vertex, &fragment, &programs[DEFAULT_PROGRAM]); rtassert(ok, "vertex-color program"); check_gl(); - ok = make_program(&chess_piece_vertex, &fragment, &resources->programs[CHESS_PIECE_PROGRAM]); + program = &programs[CHESS_PIECE_PROGRAM]; + ok = make_program("chess-piece", &chess_piece_vertex, &fragment, program); rtassert(ok, "chess-piece program"); - check_gl(); + add_uniform(program, "piece_color", UNIFORM_PIECE_COLOR); - // Program variables - GLuint programs[] = - { resources->programs[TERRAIN_PROGRAM].handle - , resources->programs[DEFAULT_PROGRAM].handle - , resources->programs[CHESS_PIECE_PROGRAM].handle - }; + struct uniform *var; + for (int i = 0; i < NUM_PROGRAMS; ++i) { + struct gpu_program *program = &programs[i]; + if (program == NULL) { + debug("program %d is NULL\n", i); + continue; + } - // uniforms shared between all shaders - for (size_t i = 0; i < ARRAY_SIZE(programs); ++i) { - GLuint handle = programs[i]; + if (program->name == NULL) { + debug("program %d name is NULL, not initialized?\n", i); + continue; + } // Program variables - resources->uniforms.camera_position = - glGetUniformLocation(handle, "camera_position"); - check_gl(); - - // TODO: more flexible uniforms - resources->uniforms.piece_color = glGetUniformLocation(handle, "piece_color"); - check_gl(); - - /* resources->uniforms.depth_vp = */ - /* glGetUniformLocation(handle, "depth_vp"); */ - /* check_gl(); */ - - resources->uniforms.depth_mvp = - glGetUniformLocation(handle, "depth_mvp"); - check_gl(); - resources->uniforms.camera_position = - glGetUniformLocation(handle, "camera_position"); - check_gl(); - - - resources->uniforms.light_intensity = - glGetUniformLocation(handle, "light_intensity"); - check_gl(); - - resources->uniforms.sky_intensity = - glGetUniformLocation(handle, "sky_intensity"); - check_gl(); - - resources->uniforms.time = - glGetUniformLocation(handle, "time"); - check_gl(); - - resources->uniforms.light_dir = - glGetUniformLocation(handle, "light_dir"); - check_gl(); - - resources->uniforms.sun_color = - glGetUniformLocation(handle, "sun_color"); - check_gl(); - - resources->uniforms.fog_on = - glGetUniformLocation(handle, "fog_on"); - check_gl(); - - /* resources->uniforms.diffuse_on = */ - /* glGetUniformLocation(handle, "diffuse_on"); */ - /* check_gl(); */ - - resources->uniforms.model = - glGetUniformLocation(handle, "model"); - check_gl(); - - resources->uniforms.mvp = - glGetUniformLocation(handle, "mvp"); - check_gl(); - - /* resources->uniforms.model_view = */ - /* glGetUniformLocation(handle, "model_view"); */ - - resources->uniforms.normal_matrix = - glGetUniformLocation(handle, "normal_matrix"); - check_gl(); - - resources->vertex_attrs[va_normal] = - (gpu_addr)glGetAttribLocation(handle, "normal"); - check_gl(); - - resources->vertex_attrs[va_position] = - (gpu_addr)glGetAttribLocation(handle, "position"); - check_gl(); - + add_uniform(program, "camera_position", UNIFORM_CAMERA_POSITION); + add_uniform(program, "depth_mvp", UNIFORM_DEPTH_MVP); + add_uniform(program, "light_intensity", UNIFORM_LIGHT_INTENSITY); + add_uniform(program, "sky_intensity", UNIFORM_SKY_INTENSITY); + add_uniform(program, "time", UNIFORM_TIME); + add_uniform(program, "light_dir", UNIFORM_LIGHT_DIR); + add_uniform(program, "sun_color", UNIFORM_SUN_COLOR); + add_uniform(program, "fog_on", UNIFORM_FOG_ON); + add_uniform(program, "model", UNIFORM_MODEL); + add_uniform(program, "mvp", UNIFORM_MVP); + add_uniform(program, "normal_matrix", UNIFORM_NORMAL_MATRIX); + + // Attributes + add_attribute(program, "normal", va_normal); + add_attribute(program, "position", va_position); + add_attribute(program, "color", va_color); } - // TODO: auto-generate these somehow? - resources->vertex_attrs[va_color] = - (gpu_addr)glGetAttribLocation(resources->programs[DEFAULT_PROGRAM] - .handle, "color"); - - /* assert(resources->attributes.color != 0xFFFFFFFF); */ - check_gl(); } @@ -227,6 +196,34 @@ static void gamma_correct(float *c, float *d) { d[2] = powf(c[2], gamma); } +static inline void uniform_3f(struct gpu_program *program, + enum uniform_id id, const float *v3) +{ + glUniform3f(program->uniforms[id].location, v3[0], v3[1], v3[2]); + check_gl(); +} + +static inline void uniform_1i(struct gpu_program *program, + enum uniform_id id, int i) +{ + glUniform1i(program->uniforms[id].location, i); + check_gl(); +} + +static inline void uniform_m4f(struct gpu_program *program, + enum uniform_id id, float *m) +{ + glUniformMatrix4fv(program->uniforms[id].location, 1, 0, m); + check_gl(); +} + +static inline void uniform_1f(struct gpu_program *program, + enum uniform_id id, float f) +{ + glUniform1f(program->uniforms[id].location, f); + check_gl(); +} + void render (struct game *game, struct render_config *config) { float gtmp[3]; struct resources *res = &game->test_resources; @@ -264,7 +261,7 @@ void render (struct game *game, struct render_config *config) { struct entity *entities = get_all_entities(&num_entities, NULL); - struct gpu_program *current_program = NULL; + struct gpu_program *program = NULL; mat4_inverse((float*)camera, view); mat4_multiply(projection, view, view_proj); @@ -290,6 +287,8 @@ void render (struct game *game, struct render_config *config) { struct entity *entity = &entities[i]; struct model *model = get_model(&entity->model_id); assert(model); + struct node *node = get_node(&entity->node_id); + assert(node); if (entity->flags & ENT_INVISIBLE) continue; @@ -297,65 +296,41 @@ void render (struct game *game, struct render_config *config) { if (config->is_depth_pass && !(entity->flags & ENT_CASTS_SHADOWS)) continue; - current_program = &game->test_resources.programs[model->shader]; + program = &game->test_resources.programs[model->shader]; - glUseProgram(current_program->handle); + glUseProgram(program->handle); check_gl(); - glUniform3f(res->uniforms.camera_position, - camera[M_X], - camera[M_Y], - camera[M_Z]); - check_gl(); - - if (entity->flags & ENT_IS_WHITE) - glUniform3f(res->uniforms.piece_color, 0.9f, 0.9f, 0.9f); - else - glUniform3f(res->uniforms.piece_color, 0.2f, 0.2f, 0.2f); - check_gl(); - - glUniform1i(res->uniforms.fog_on, res->fog_on); - check_gl(); + uniform_3f(program, UNIFORM_CAMERA_POSITION, &camera[M_X]); - glUniform3f(res->uniforms.light_dir, light[0], light[1], light[2]); - check_gl(); + if (model->shader == CHESS_PIECE_PROGRAM) { + if (entity->flags & ENT_IS_WHITE) + uniform_3f(program, UNIFORM_PIECE_COLOR, V3(0.9f, 0.9f, 0.9f)); + else + uniform_3f(program, UNIFORM_PIECE_COLOR, V3(0.2f, 0.2f, 0.2f)); + } - glUniform1f(res->uniforms.light_intensity, res->light_intensity); - check_gl(); - - glUniform1f(res->uniforms.sky_intensity, sky_intensity); - check_gl(); - - glUniform3f(res->uniforms.sun_color, - res->sun_color[0], - res->sun_color[1], - res->sun_color[2]); - check_gl(); - - struct node *node = get_node(&entity->node_id); - assert(node); - if (node == NULL) - return; + uniform_1i(program, UNIFORM_FOG_ON, res->fog_on); + uniform_3f(program, UNIFORM_LIGHT_DIR, light); + uniform_1f(program, UNIFORM_LIGHT_INTENSITY, res->light_intensity); + uniform_1f(program, UNIFORM_SKY_INTENSITY, sky_intensity); + uniform_3f(program, UNIFORM_SUN_COLOR, res->sun_color); mat4_multiply(view_proj, node->mat, mvp); mat4_copy(node->mat, model_view); mat4_multiply(config->depth_vp, model_view, depth_mvp); - glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, depth_mvp); - check_gl(); - - glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); - check_gl(); - - glUniformMatrix4fv(res->uniforms.model, 1, 0, node->mat); - check_gl(); + uniform_m4f(program, UNIFORM_DEPTH_MVP, depth_mvp); + uniform_m4f(program, UNIFORM_MVP, mvp); + uniform_m4f(program, UNIFORM_MODEL, node->mat); - recalc_normals(res->uniforms.normal_matrix, model_view, normal_matrix); + recalc_normals(program->uniforms[UNIFORM_NORMAL_MATRIX].location, + model_view, normal_matrix); check_gl(); struct geometry *geo = get_geometry(&model->geom_id); /* debug("geo node %s\n", node->label); */ assert(geo); - render_geometry(geo, res->vertex_attrs, current_program); + render_geometry(geo, program->vertex_attrs, program); check_gl(); } diff --git a/src/shader.c b/src/shader.c @@ -199,7 +199,8 @@ int reload_program(struct gpu_program *program) { return 2; } - ok = make_program_from_shaders(new_shaders_p, n_shaders, &new_program); + ok = make_program_from_shaders(program->name, new_shaders_p, + n_shaders, &new_program); if (!ok) { for (int i = 0; i < n_shaders; i++) { @@ -214,16 +215,17 @@ int reload_program(struct gpu_program *program) { #endif int -make_program(struct shader *vertex, +make_program(const char *name, + struct shader *vertex, struct shader *fragment, struct gpu_program *program) { struct shader *shaders[] = { vertex, fragment }; - return make_program_from_shaders(shaders, 2, program); + return make_program_from_shaders(name, shaders, 2, program); } -int -make_program_from_shaders(struct shader **shaders, int n_shaders, struct gpu_program *program) +int make_program_from_shaders(const char *name, struct shader **shaders, + int n_shaders, struct gpu_program *program) { GLint program_ok; @@ -231,6 +233,7 @@ make_program_from_shaders(struct shader **shaders, int n_shaders, struct gpu_pro program->handle = glCreateProgram(); check_gl(); program->n_shaders = n_shaders; + program->name = name; assert(n_shaders <= MAX_SHADERS); for (int i = 0; i < n_shaders; i++) { diff --git a/src/shader.h b/src/shader.h @@ -3,13 +3,13 @@ #include <time.h> #include "gl.h" +#include "vbo.h" #define SHADER(f) "etc/shaders/" f #define MAX_SHADER_INCLUDES 16 #define MAX_INCLUDE_FNAME_LEN 64 #define MAX_SHADERS 5 -#define MAX_UNIFORMS 32 struct shader { GLenum type; @@ -21,10 +21,40 @@ struct shader { time_t load_mtime; }; +enum uniform_id { + UNIFORM_AMBIENT_STR, + UNIFORM_CAMERA_POSITION, + UNIFORM_DEPTH_MVP, + UNIFORM_DEPTH_VP, + UNIFORM_DIFFUSE_ON, + UNIFORM_FOG_ON, + UNIFORM_LIGHT_DIR, + UNIFORM_LIGHT_INTENSITY, + UNIFORM_MODEL, + UNIFORM_MODEL_VIEW, + UNIFORM_MVP, + UNIFORM_NORMAL_MATRIX, + UNIFORM_SKY_INTENSITY, + UNIFORM_SUN_COLOR, + UNIFORM_TIME, + UNIFORM_VIEW_PROJ, + UNIFORM_PIECE_COLOR, + MAX_UNIFORMS +}; + +struct uniform { + enum uniform_id id; + const char *name; + int location; +}; + struct gpu_program { struct shader shaders[MAX_SHADERS]; + struct uniform uniforms[MAX_UNIFORMS]; + gpu_addr vertex_attrs[MAX_VERTEX_ATTRS]; int n_shaders; GLuint handle; + const char *name; }; #define NO_GEOM_SHADER NULL @@ -33,14 +63,13 @@ int reload_program(struct gpu_program *program); int make_shader(GLenum type, const char *filename, struct shader *shader); void init_gpu_program(struct gpu_program *program); -int make_program_from_shaders(struct shader **shaders, +int make_program_from_shaders(const char *name, + 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); +int make_program(const char *name, struct shader *vertex, struct shader *fragment, struct gpu_program *program); #endif /* POLYADVENT_SHADER_H */ diff --git a/src/skybox.c b/src/skybox.c @@ -86,7 +86,7 @@ void create_skybox(struct skybox *skybox, struct gpu_program *program) { make_shader(GL_FRAGMENT_SHADER, SHADER("skybox.f.glsl"), &frag); check_gl(); - ok = make_program_from_shaders(shaders, 2, skybox->program); + ok = make_program("skybox", &vertex, &frag, skybox->program); assert(ok); check_gl(); diff --git a/src/ui.c b/src/ui.c @@ -106,7 +106,7 @@ void create_ui(struct ui *ui, int width, int height, struct gpu_program *shader) 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("ui", &vertex, &fragment, ui->shader); assert(ok && "ui program"); GLuint program = ui->shader->handle;