polyadvent

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

commit c2d82552009445893fd84e89c1722e7bb0e32818
parent abb67a77d710c242521dd9823bfa55ba55ac1ad1
Author: William Casarin <jb55@jb55.com>
Date:   Sun,  4 Nov 2018 14:13:39 -0800

entity system, shadow refactors

Diffstat:
Metc/shaders/lighting.glsl | 23+++++++++++------------
Metc/shaders/standard_vtxos.glsl | 2++
Metc/shaders/terrain.g.glsl | 4++--
Metc/shaders/terrain.te.glsl | 2+-
Metc/shaders/test.f.glsl | 24+++++-------------------
Metc/shaders/uniforms.glsl | 2+-
Msrc/entity.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/entity.h | 22+++++++++++++---------
Msrc/game.c | 59+++++++++++++++++++++++++++++++++--------------------------
Msrc/game.h | 4+++-
Msrc/model.c | 6++++--
Msrc/model.h | 1+
Msrc/render.c | 21+++++++++++++--------
Msrc/terrain.c | 274++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/terrain.h | 9+++++----
Msrc/update.c | 156++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/update.h | 3++-
Msrc/window.c | 5++++-
18 files changed, 408 insertions(+), 305 deletions(-)

diff --git a/etc/shaders/lighting.glsl b/etc/shaders/lighting.glsl @@ -19,29 +19,28 @@ vec3 gamma_correct(vec3 color) { return pow(color, vec3(1.0/2.2)); } -vec3 standard_light(vec3 color, vec3 position, vec3 normal) { - vec4 trans_normal = normal_matrix * vec4(normal, 1.0); - +vec3 standard_light(vec3 color, vec4 position, vec4 normal) { // 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 ambient_str = 0.25; float spec_str = 0.8 * light_intensity; + vec4 trans_normal = normal_matrix * normal; + vec3 L = light_dir; + vec3 N = normalize(trans_normal.xyz); + float cos_theta = max(0.0, dot(L,N)); + // float light_intensity = light_intensity * 0.01; // too much ambient during daytime is making things look weird // ambient_str =- light_intensity * ambient_str; - vec3 ray = camera_position - position; + vec3 ray = camera_position - position.xyz; vec3 view_dir = normalize(ray); - float distance = length(ray); - float attenuation = 1.0 / distance; - vec3 L = light_dir; - vec3 N = normalize(trans_normal.xyz); - float brightness = max(0.0, dot(L,N)) * light_intensity; + float brightness = cos_theta * light_intensity; // brightness += clouds(position); @@ -55,12 +54,12 @@ vec3 standard_light(vec3 color, vec3 position, vec3 normal) { 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(normal, halfway_dir), 0.0), shiny); + spec = energy_conservation * pow(max(dot(normal.xyz, halfway_dir), 0.0), shiny); } else { const float energy_conservation = ( 2.0 + shiny ) / ( 2.0 * pi ); - vec3 reflect_dir = reflect(-light_dir, normal); // phong + vec3 reflect_dir = reflect(-light_dir, normal.xyz); // 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,5 +1,7 @@ vec4 v4_pos = vec4(position, 1.0); data_out.normal = normal; +data_out.position = position; data_out.color_smooth = data_out.color = color; data_out.shadow_coord = depth_mvp * v4_pos; data_out.frag_pos = (world * v4_pos).xyz; +// TODO: move shadow coord calc from frag to here diff --git a/etc/shaders/terrain.g.glsl b/etc/shaders/terrain.g.glsl @@ -23,9 +23,9 @@ void main() { vertex.color = vertices[i].color; vertex.color_smooth = vertices[i].color_smooth; vertex.normal = vertices[i].normal; - vertex.shadow_coord = depth_mvp * v4_pos; + // vertex.shadow_coord = depth_mvp * v4_pos; vertex.frag_pos = (world * v4_pos).xyz; - // vertex.shadow_coord = vertices[i].shadow_coord; + vertex.shadow_coord = vertices[i].shadow_coord; // vertex.frag_pos = vertices[i].frag_pos; // gl_Position = mvp * vec4(400.0 + i * 50.0, 300.0 + i * 50.0, 200.0 + i * 50.0, 1.0); diff --git a/etc/shaders/terrain.te.glsl b/etc/shaders/terrain.te.glsl @@ -28,7 +28,7 @@ void main() 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.shadow_coord = depth_mvp * data_in[0].shadow_coord; data_out.frag_pos = (world * v).xyz; } diff --git a/etc/shaders/test.f.glsl b/etc/shaders/test.f.glsl @@ -12,17 +12,18 @@ in shader_data { uniform sampler2D shadow_map; #include lighting.glsl +#include shadows.glsl #include fog.glsl void main() { const float smoothness = 0.0; - float visibility = 1.0; - vec4 shadow_sample = texture(shadow_map, vertex.shadow_coord.xy); vec3 v_ray = camera_position - vertex.frag_pos; + vec4 v4_pos = vec4(vertex.position, 1.0); + vec4 v4_normal = vec4(vertex.normal, 1.0); // vec3 color = vertex.color * (1.0-smoothness) // + color_smooth * smoothness; - vec3 color = standard_light(vertex.color, vertex.position, vertex.normal); + vec3 color = standard_light(vertex.color, v4_pos, v4_normal); if (fog_on) { vec3 fog = apply_fog(color, length(v_ray), camera_position, v_ray); @@ -30,22 +31,7 @@ void main() { color = fog; } - float bias = 0.006; - bool in_shadow = - shadow_sample.z < vertex.shadow_coord.z - bias - && shadow_sample.y < 1.0; - - if (light_dir.z > 0.0 && in_shadow) { - float factor = 1.0/(dot(light_dir, vec3(0.0, 0.0, 1.0))); - // float factor = 1.0; - visibility = clamp(0.2 * factor, 0.5, 1.0); - // visibility = shadow_sample; - } - - // float factor = 1.0/(dot(light_dir, vec3(0.0, 0.0, 1.0))); - color *= visibility; - // color += shadow_sample.z * factor; - // float dist = length(camera_position - vertex.position); + color *= shadow_strength(v4_pos, v4_normal, vertex.shadow_coord); frag_color = vec4(color, 1.0); } diff --git a/etc/shaders/uniforms.glsl b/etc/shaders/uniforms.glsl @@ -4,7 +4,7 @@ uniform bool fog_on; uniform float sky_intensity; uniform float light_intensity; uniform mat4 depth_mvp; -uniform mat4 model_view; +uniform mat4 depth_vp; uniform mat4 mvp; uniform mat4 normal_matrix; uniform mat4 world; diff --git a/src/entity.c b/src/entity.c @@ -6,29 +6,99 @@ #define DEF_NUM_ENTITIES 1024 -struct entity_id { - u32 index; +struct entity_system { + struct entity *entities; + struct entity_id *ids; + u32 entity_count; u32 generation; }; -void init_entity(struct entity *ent) { +static u64 entity_uuids = 0; + +static struct entity_system esys; + +struct entity *get_all_entities(u32 *count, struct entity_id **ids) { + if (count != NULL) + *count = esys.entity_count; + if (ids != NULL) + *ids = esys.ids; + return esys.entities; +} + +struct entity *init_entity(struct entity *ent) { node_init(&ent->node); - ent->casts_shadows = 0; + init_model(&ent->model); + ent->casts_shadows = 1; + return ent; } -struct entity *get_entity(struct entity_system *system, struct entity_id id) { - assert(id.generation <= system->generation); - if (id.generation < system->generation) +struct entity *get_entity_pure(struct entity_id id) { + struct entity_id pure_id; + pure_id = id; + + return get_entity(&pure_id); +} + +struct entity *get_entity(struct entity_id *id) { + struct entity_id *new_id; + // rollover is ok + /* assert(->generation <= esys.generation); */ + if (id->generation != esys.generation) { + // try to find uuid in new memory layout + for (u32 i = 0; i < esys.entity_count; i++) { + new_id = &esys.ids[i]; + if (new_id->uuid == id->uuid) { + id->index = new_id->index; + id->generation = esys.generation; + return &esys.entities[id->index]; + } + } + + // entity was deleted return NULL; - return &system->entities[id.index]; + } + return &esys.entities[id->index]; +} + +static inline struct entity_id new_id() { + return (struct entity_id){ + .index = esys.entity_count, + .uuid = entity_uuids++, + .generation = esys.generation, + }; +} + +static inline struct entity *new_uninitialized_entity(struct entity_id *id) { + struct entity_id fresh_id; + fresh_id = new_id(); + + if (id) + *id = fresh_id; + + return &esys.entities[esys.entity_count++]; +} + +struct entity *new_entity(struct entity_id *id) { + return init_entity(new_uninitialized_entity(id)); +} + +struct entity *add_entity(struct entity *e, struct entity_id *id) { + struct entity *new = new_uninitialized_entity(id); + *new = *e; + return new; +} + + +void destroy_entity_system() { + free(esys.entities); } -void init_entity_system(struct entity_system *system) { - system->generation = 0; - system->entities = calloc(DEF_NUM_ENTITIES, sizeof(*system->entities)); +void init_entity_system() { + esys.generation = 0; + esys.entities = calloc(DEF_NUM_ENTITIES, sizeof(*esys.entities)); - system->handles = - calloc(DEF_NUM_ENTITIES, sizeof(*system->handles)); + esys.ids = + calloc(DEF_NUM_ENTITIES, sizeof(*esys.ids)); } diff --git a/src/entity.h b/src/entity.h @@ -5,26 +5,30 @@ #include "node.h" #include "model.h" +enum entity_flags { + ENT_FLAG_PLAYER = 1 << 0, +}; + struct entity { struct node node; struct model model; + u32 flags; float velocity[3]; float accel[3]; int casts_shadows; }; -struct entity_id; - -struct entity_system { - struct entity *entities; - struct entity_id *handles; - int entity_count; +struct entity_id { + u64 uuid; + u32 index; u32 generation; }; -void init_entity(struct entity *); -void init_entity_system(struct entity_system *); -struct entity *get_entity(struct entity_system *, struct entity_id); +struct entity *init_entity(struct entity *); +void init_entity_system(); +struct entity *get_entity(struct entity_id *); +struct entity *get_all_entities(u32 *count, struct entity_id **ids); +struct entity *new_entity(struct entity_id *id); #endif /* ENTITY_H */ diff --git a/src/game.c b/src/game.c @@ -25,17 +25,25 @@ static void camera_update(struct node *node) { mat4_multiply(persp, mat, mat); } +struct entity *get_player(struct resources *res) { + struct entity *player = get_entity(&res->player_id); + assert(player); + return player; +} + void game_init(struct game *game, int width, int height) { init_gl(&game->test_resources, width, height); + init_entity_system(); check_gl(); + float pos[3]; struct resources *res = &game->test_resources; mat4 *mvp = res->test_mvp; struct node *root = &res->root; struct node *camera = &res->camera; struct node *sun_camera = &res->sun_camera; - struct entity *player = &res->player; struct terrain *terrain = &game->terrain; + struct entity *player; mat4 *light_dir = res->light_dir; int ok = 0; @@ -58,9 +66,7 @@ void game_init(struct game *game, int width, int height) { check_gl(); - terrain_init(terrain); - terrain->entity.model.shading = SHADING_TERRAIN; - terrain->size = size; + init_terrain(terrain, size); mat4_id(mvp); @@ -79,16 +85,6 @@ void game_init(struct game *game, int width, int height) { res->sun_color[1] = 0.6; res->sun_color[2] = 0.7; - /* vec3(0.5,0.6,0.7); */ - - // BRB: shadow mapping next! - - // FBO STUFF - init_fbo(&res->shadow_buffer); - resize_fbos(game, width, height); - - // FBO STUFF END - game->test_resources.fog_on = 1; game->test_resources.diffuse_on = 0; @@ -100,32 +96,43 @@ void game_init(struct game *game, int width, int height) { node_init(camera); node_init(sun_camera); - init_entity(&terrain->entity); - init_entity(player); - player->casts_shadows = 1; - terrain->entity.casts_shadows = 0; + // ENTITIES - // player init + // player entity + player = new_entity(&res->player_id); ok = load_model(&player->model, "pirate-officer"); assert(ok); - player->model.shading = SHADING_VERT_COLOR; player->node.label = "player"; + node_attach(&player->node, root); + node_translate(&player->node, V3(terrain->size/2.,terrain->size/2.,0.0)); + + struct entity *tower = new_entity(NULL); + ok = load_model(&tower->model, "tower"); + assert(ok); + tower->node.label = "tower"; + node_attach(&tower->node, &player->node); + node_translate(&tower->node, V3(0.0, 40.0, 0.0)); + + + // END ENTITIES + + + // player init root->label = "root"; camera->label = "camera"; - terrain->entity.node.label = "terrain_node"; - node_attach(&player->node, root); node_attach(camera, &player->node); quat_axis_angle(V3(1,0,0), -45, camera->orientation); - node_translate(&player->node, V3(terrain->size/2.,terrain->size/2.,0.0)); - node_rotate(camera, V3(100, 0, 0)); node_translate(camera, V3(0,-40,20)); - terrain->entity.node.pos[2] = 20.0; - input_init(&game->input); + + // FBO STUFF + init_fbo(&res->shadow_buffer); + resize_fbos(player, &res->shadow_buffer, res->proj_ortho, width, height); + // FBO STUFF END } diff --git a/src/game.h b/src/game.h @@ -43,6 +43,7 @@ struct resources { GLint sun_color; GLint mvp; GLint depth_mvp; + GLint depth_vp; GLint normal_matrix; GLint view; GLint time; @@ -55,7 +56,7 @@ struct resources { struct attributes attributes; struct node root; - struct entity player; + struct entity_id player_id; struct orbit orbit_camera; struct node camera; struct node sun_camera; @@ -81,6 +82,7 @@ struct game { struct terrain terrain; }; +struct entity *get_player(struct resources *); void game_init(struct game *game, int width, int height); void should_update(struct game *game); diff --git a/src/model.c b/src/model.c @@ -2,14 +2,16 @@ #include "model.h" #include "ply.h" +void init_model(struct model *model) { + model->shading = SHADING_VERT_COLOR; + init_geometry(&model->geom); +} int load_model(struct model *model, const char *name) { static char path[128] = {0}; int ok = 0; - init_geometry(&model->geom); - // Load mesh snprintf(path, 128, "data/models/%s.ply", name); ok = parse_ply(path, &model->geom); diff --git a/src/model.h b/src/model.h @@ -20,6 +20,7 @@ struct model { }; +void init_model(struct model *model); int load_model(struct model *model, const char *name); diff --git a/src/render.c b/src/render.c @@ -140,6 +140,10 @@ init_gl(struct resources *resources, int width, int height) { glGetUniformLocation(handle, "camera_position"); check_gl(); + resources->uniforms.depth_vp = + glGetUniformLocation(handle, "depth_vp"); + check_gl(); + resources->uniforms.depth_mvp = glGetUniformLocation(handle, "depth_mvp"); check_gl(); @@ -250,11 +254,10 @@ void render (struct game *game, struct render_config *config) { mat4 *light = res->light_dir; float *camera = config->camera; + u32 num_entities; - struct entity *entities[] = - { &game->terrain.entity - , &game->test_resources.player - }; + struct entity *entities = + get_all_entities(&num_entities, NULL); struct gpu_program *current_program = NULL; @@ -268,19 +271,19 @@ void render (struct game *game, struct render_config *config) { mat4_multiply(projection, view, view_proj); if (config->is_depth_pass) { - /* glCullFace(GL_FRONT); */ + glDisable(GL_CULL_FACE); mat4_multiply(bias_matrix, view_proj, config->depth_vp); } else { glCullFace(GL_BACK); } - for (size_t i = 0; i < ARRAY_SIZE(entities); ++i) { - struct entity *entity = entities[i]; + for (u32 i = 0; i < num_entities; ++i) { + struct entity *entity = &entities[i]; if (config->is_depth_pass && !entity->casts_shadows) continue; - // TODO this is a bit wonky, refactor this + // TODO this is a bit wonky, refactor this current_program = i == 0 ? terrain_program : default_program; glUseProgram(current_program->handle); check_gl(); @@ -317,6 +320,8 @@ void render (struct game *game, struct render_config *config) { check_gl(); glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, depth_mvp); check_gl(); + glUniformMatrix4fv(res->uniforms.depth_vp, 1, 0, config->depth_vp); + check_gl(); glUniformMatrix4fv(res->uniforms.model_view, 1, 0, model_view); check_gl(); glUniformMatrix4fv(res->uniforms.world, 1, 0, entity->node.mat); diff --git a/src/terrain.c b/src/terrain.c @@ -41,146 +41,166 @@ void deriv(noisefn fn, void* data, double x, double y, double z1, double *dx, do *dy = (zy - z1)/h; } -void -terrain_init(struct terrain *terrain) { - terrain->samples = NULL; - terrain->n_samples = 0; - terrain->fn = 0; - // TODO: init model - init_geometry(&terrain->entity.model.geom); +void reset_terrain(struct terrain *terrain, float size) { + terrain->samples = NULL; + terrain->n_samples = 0; + terrain->fn = 0; + terrain->size = size; + + struct entity *ent = get_entity(&terrain->entity_id); + assert(ent); +} + +void init_terrain(struct terrain *terrain, float size) { + struct entity *ent; + + ent = new_entity(&terrain->entity_id); + assert(terrain->entity_id.uuid == 0); + ent->model.shading = SHADING_TERRAIN; + ent->node.label = "terrain_node"; + ent->casts_shadows = 0; + + // this is scale for some reason!? + ent->node.pos[2] = 20.0; + + reset_terrain(terrain, size); } double offset_fn(struct terrain* terrain, double x, double y) { - struct perlin_settings *perlin = &terrain->settings; - double ox = perlin->ox; - double oy = perlin->oy; - return old_noisy_boi(terrain, ox+x, oy+y); + struct perlin_settings *perlin = &terrain->settings; + double ox = perlin->ox; + double oy = perlin->oy; + return old_noisy_boi(terrain, ox+x, oy+y); } -void -terrain_create(struct terrain *terrain) { - u32 i; - const double size = terrain->size; - - float tmp1[3], tmp2[3]; - assert(terrain->n_samples > 0); - del_point2d_t *points = calloc(terrain->n_samples, sizeof(*points)); - - float *verts = calloc(terrain->n_samples * 3, sizeof(*verts)); - /* float *normals = calloc(terrain->n_samples * 3, sizeof(*verts)); */ - - terrain->fn = offset_fn; - - // 100 random samples from our noise function - for (i = 0; i < (u32)terrain->n_samples; i++) { - int n = i*3; - double x, y; - /* double dx, dy; */ - - x = terrain->samples[i].x; - y = terrain->samples[i].y; - - double z = terrain->fn(terrain, x, y); - - points[i].x = x; - points[i].y = y; - - verts[n] = (float)x; - verts[n+1] = (float)y; - - static const double limit = 1.4; - if (x < limit || x > size-limit || y < limit || y > size-limit) - verts[n+2] = 0; - else - verts[n+2] = (float)z; - } - - delaunay2d_t *del = delaunay2d_from(points, terrain->n_samples); - tri_delaunay2d_t *tri = tri_delaunay2d_from(del); - - int num_verts = tri->num_triangles * 3; - float *del_verts = calloc(num_verts * 3, sizeof(*del_verts)); - float *del_norms = calloc(num_verts * 3, sizeof(*del_norms)); - u32 *del_indices = calloc(num_verts, sizeof(*del_indices)); - - /// XXX (perf): we should be able to do this directly from del instead of - /// triangulating with tri - for (i = 0; i < tri->num_triangles; ++i) { - int nv = i * 3; - int ndv = i * 9; - - int p[3] = { - tri->tris[nv + 0], - tri->tris[nv + 1], - tri->tris[nv + 2], - }; - - float *v[3] = { - &verts[p[0]*3], - &verts[p[1]*3], - &verts[p[2]*3] - }; - - del_verts[ndv+0] = v[0][0]; - del_verts[ndv+1] = v[0][1]; - del_verts[ndv+2] = v[0][2]; - - del_verts[ndv+3] = v[1][0]; - del_verts[ndv+4] = v[1][1]; - del_verts[ndv+5] = v[1][2]; - - del_verts[ndv+6] = v[2][0]; - del_verts[ndv+7] = v[2][1]; - del_verts[ndv+8] = v[2][2]; - - // centroid normals - /* float c[3]; */ - /* c[0] = (v[0][0] + v[1][0] + v[2][0]) / 3.0; */ - /* c[1] = (v[0][1] + v[1][1] + v[2][1]) / 3.0; */ - /* c[2] = (v[0][2] + v[1][2] + v[2][2]) / 3.0; */ - /* double dx, dy; */ - /* deriv((noisefn)terrain->fn, terrain, c[0], c[1], c[2], &dx, &dy); */ - /* 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); - - for (int j = 0; j < 9; ++j) { - del_norms[ndv+j] = tmp2[j%3]; +void create_terrain(struct terrain *terrain) { + u32 i; + const double size = terrain->size; + + float tmp1[3], tmp2[3]; + assert(terrain->n_samples > 0); + del_point2d_t *points = calloc(terrain->n_samples, sizeof(*points)); + + float *verts = calloc(terrain->n_samples * 3, sizeof(*verts)); + /* float *normals = calloc(terrain->n_samples * 3, sizeof(*verts)); */ + + terrain->fn = offset_fn; + + // 100 random samples from our noise function + for (i = 0; i < (u32)terrain->n_samples; i++) { + int n = i*3; + double x, y; + /* double dx, dy; */ + + x = terrain->samples[i].x; + y = terrain->samples[i].y; + + double z = terrain->fn(terrain, x, y); + + points[i].x = x; + points[i].y = y; + + verts[n] = (float)x; + verts[n+1] = (float)y; + + static const double limit = 1.4; + if (x < limit || x > size-limit || y < limit || y > size-limit) + verts[n+2] = 0; + else + verts[n+2] = (float)z; + } + + delaunay2d_t *del = delaunay2d_from(points, terrain->n_samples); + tri_delaunay2d_t *tri = tri_delaunay2d_from(del); + + int num_verts = tri->num_triangles * 3; + float *del_verts = calloc(num_verts * 3, sizeof(*del_verts)); + float *del_norms = calloc(num_verts * 3, sizeof(*del_norms)); + u32 *del_indices = calloc(num_verts, sizeof(*del_indices)); + + /// XXX (perf): we should be able to do this directly from del instead of + /// triangulating with tri + for (i = 0; i < tri->num_triangles; ++i) { + int nv = i * 3; + int ndv = i * 9; + + int p[3] = { + tri->tris[nv + 0], + tri->tris[nv + 1], + tri->tris[nv + 2], + }; + + float *v[3] = { + &verts[p[0]*3], + &verts[p[1]*3], + &verts[p[2]*3] + }; + + del_verts[ndv+0] = v[0][0]; + del_verts[ndv+1] = v[0][1]; + del_verts[ndv+2] = v[0][2]; + + del_verts[ndv+3] = v[1][0]; + del_verts[ndv+4] = v[1][1]; + del_verts[ndv+5] = v[1][2]; + + del_verts[ndv+6] = v[2][0]; + del_verts[ndv+7] = v[2][1]; + del_verts[ndv+8] = v[2][2]; + + // centroid normals + /* float c[3]; */ + /* c[0] = (v[0][0] + v[1][0] + v[2][0]) / 3.0; */ + /* c[1] = (v[0][1] + v[1][1] + v[2][1]) / 3.0; */ + /* c[2] = (v[0][2] + v[1][2] + v[2][2]) / 3.0; */ + /* double dx, dy; */ + /* deriv((noisefn)terrain->fn, terrain, c[0], c[1], c[2], &dx, &dy); */ + /* 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); + + for (int j = 0; j < 9; ++j) { + del_norms[ndv+j] = tmp2[j%3]; + } + + del_indices[nv+0] = nv+0; + del_indices[nv+1] = nv+1; + del_indices[nv+2] = nv+2; } - del_indices[nv+0] = nv+0; - del_indices[nv+1] = nv+1; - del_indices[nv+2] = nv+2; - } + /* printf("faces %d tris %d points %d\n", */ + /* del->num_faces, tri->num_triangles, tri->num_points); */ - /* printf("faces %d tris %d points %d\n", */ - /* del->num_faces, tri->num_triangles, tri->num_points); */ + struct entity *ent = get_entity(&terrain->entity_id); + assert(ent); - terrain->entity.model.geom.num_verts = num_verts; - terrain->entity.model.geom.vertices = (float*)del_verts; - terrain->entity.model.geom.normals = (float*)del_norms; - terrain->entity.model.geom.indices = (u32*)del_indices; - terrain->entity.model.geom.num_indices = num_verts; + ent->model.geom.num_verts = num_verts; + ent->model.geom.vertices = (float*)del_verts; + ent->model.geom.normals = (float*)del_norms; + ent->model.geom.indices = (u32*)del_indices; + ent->model.geom.num_indices = num_verts; - make_buffer_geometry(&terrain->entity.model.geom); + make_buffer_geometry(&ent->model.geom); - delaunay2d_release(del); - tri_delaunay2d_release(tri); + delaunay2d_release(del); + tri_delaunay2d_release(tri); - free(points); - free(verts); - free(del_verts); - free(del_norms); - free(del_indices); + free(points); + free(verts); + free(del_verts); + free(del_norms); + free(del_indices); } -void terrain_destroy(struct terrain *terrain) { - destroy_buffer_geometry(&terrain->entity.model.geom); +void destroy_terrain(struct terrain *terrain) { + struct entity *ent = get_entity(&terrain->entity_id); + assert(ent); + destroy_buffer_geometry(&ent->model.geom); } diff --git a/src/terrain.h b/src/terrain.h @@ -21,7 +21,7 @@ struct perlin_settings { struct terrain { - struct entity entity; + struct entity_id entity_id; struct perlin_settings settings; struct point *samples; double (*fn)(struct terrain *, double, double); @@ -31,9 +31,10 @@ struct terrain { double old_noisy_boi(struct terrain *, double x, double y); -void terrain_init(struct terrain *terrain); -void terrain_create(struct terrain *terrain); -void terrain_destroy(struct terrain *terrain); +void init_terrain(struct terrain *terrain, float size); +void reset_terrain(struct terrain *terrain, float size); +void create_terrain(struct terrain *terrain); +void destroy_terrain(struct terrain *terrain); #endif /* POLYADVENT_TERRAIN_H */ diff --git a/src/update.c b/src/update.c @@ -84,73 +84,73 @@ static void remap_samples(struct point *points, int n_samples, } } -void update_terrain(struct game *game) { - static int first = 1; - static float last_scale = -1.0; - - struct perlin_settings *ts = &game->terrain.settings; - struct node *tnode = &game->terrain.entity.node; - struct terrain *terrain = &game->terrain; - - printf("updating terrain\n"); - - if (first) { - terrain_init(terrain); - tnode->pos[0] = rand_0to1() * 100000.0; - tnode->pos[1] = rand_0to1() * 100000.0; - first = 0; - } - - ts->ox = tnode->pos[0]; - ts->oy = tnode->pos[1]; +void update_terrain(struct terrain *terrain) { + static int first = 1; + static float last_scale = -1.0; + + struct entity *ent = get_entity(&terrain->entity_id); + assert(ent); + struct perlin_settings *ts = &terrain->settings; + struct node *tnode = &ent->node; + + printf("updating terrain\n"); + + if (first) { + reset_terrain(terrain, terrain->size); + tnode->pos[0] = rand_0to1() * terrain->size; + tnode->pos[1] = rand_0to1() * terrain->size; + first = 0; + } - double scale = tnode->pos[2] * 0.0015; - if (scale == 0) scale = 1.0; + ts->ox = tnode->pos[0]; + ts->oy = tnode->pos[1]; - printf("terrain %f %f %f\n", tnode->pos[0], tnode->pos[1], tnode->pos[2]); + double scale = tnode->pos[2] * 0.0015; + if (scale == 0) scale = 1.0; - /* ts.o1s = fabs(sin(1/n) * 0.25); */ - /* ts.o1 = fabs(cos(n*0.2) * 0.5); */ - /* ts.o2s = fabs(cos(n+2) * 0.5); */ - /* ts.o2 = fabs(sin(n*0.02) * 2); */ - ts->freq = scale * 0.05; - ts->amplitude = 50.0; + printf("terrain %f %f %f\n", tnode->pos[0], tnode->pos[1], tnode->pos[2]); - if (terrain->fn) - terrain_destroy(&game->terrain); + /* ts.o1s = fabs(sin(1/n) * 0.25); */ + /* ts.o1 = fabs(cos(n*0.2) * 0.5); */ + /* ts.o2s = fabs(cos(n+2) * 0.5); */ + /* ts.o2 = fabs(sin(n*0.02) * 2); */ + ts->freq = scale * 0.05; + ts->amplitude = 50.0; + /* if (terrain->fn) */ + /* destroy_terrain(terrain); */ - /* const double pdist = min(5.0, max(1.1, 1.0/scale*1.4)); */ + /* const double pdist = min(5.0, max(1.1, 1.0/scale*1.4)); */ - /* printf("pdist %f\n", pdist); */ + /* printf("pdist %f\n", pdist); */ - if (last_scale == -1.0 || fabs(scale - last_scale) > 0.00001) { - printf("generating new samples\n"); + if (last_scale == -1.0 || fabs(scale - last_scale) > 0.00001) { + printf("generating new samples\n"); - if (terrain->samples) - free(terrain->samples); + if (terrain->samples) + free(terrain->samples); - int n_samples = - (terrain->size * game->terrain.size) / (scale * scale); + int n_samples = + (terrain->size * terrain->size) / (scale * scale); - /* struct point *samples = */ - /* uniform_samples(n_samples, game->terrain.size); */ + /* struct point *samples = */ + /* uniform_samples(n_samples, game->terrain.size); */ - static const double pdist = 24.0; + static const double pdist = 24.0; - struct point *samples = - poisson_disk_samples(pdist, game->terrain.size, 30, &n_samples); + struct point *samples = + poisson_disk_samples(pdist, terrain->size, 30, &n_samples); - /* remap_samples(samples, n_samples, game->terrain.size); */ + /* remap_samples(samples, n_samples, game->terrain.size); */ - /* draw_samples(samples, pdist, n_samples, game->terrain.size); */ + /* draw_samples(samples, pdist, n_samples, game->terrain.size); */ - terrain->samples = samples; - terrain->n_samples = n_samples; - } + terrain->samples = samples; + terrain->n_samples = n_samples; + } - last_scale = scale; - terrain_create(&game->terrain); + last_scale = scale; + create_terrain(terrain); } static void player_terrain_collision(struct terrain *terrain, struct entity *player) { @@ -161,7 +161,7 @@ static void player_terrain_collision(struct terrain *terrain, struct entity *pla float player_z = player->node.pos[2]; float terrain_z = - terrain->fn(terrain, player->node.pos[0], player->node.pos[1]) + 5.0; + terrain->fn(terrain, player->node.pos[0], player->node.pos[1]); float inset = min(0.0, player_z - terrain_z); @@ -172,9 +172,8 @@ static void player_terrain_collision(struct terrain *terrain, struct entity *pla } -static void player_movement(struct game *game) { - struct resources *res = &game->test_resources; - movement(game, &res->player.node, 2.0); +static void player_movement(struct game *game, struct entity *player) { + movement(game, &player->node, 2.0); /* vec3 *camera_world = node_world(&res->camera); */ /* float cam_terrain_z = */ @@ -210,37 +209,36 @@ static int try_reload_shaders(struct resources *res) { } #endif -void resize_fbos(struct game *game, int width, int height) { - struct resources *res = &game->test_resources; - - if (res->shadow_buffer.handle) { +void resize_fbos(struct entity *player, struct fbo *shadow_buffer, + float *m4_ortho, int width, int height) { + if (shadow_buffer->handle) { // TODO: remove once delete_fbo deletes attachments - glDeleteTextures(1, &res->shadow_buffer.attachments[1]); - glDeleteRenderbuffers(1, &res->shadow_buffer.attachments[0]); - delete_fbo(&res->shadow_buffer); + glDeleteTextures(1, &shadow_buffer->attachments[1]); + glDeleteRenderbuffers(1, &shadow_buffer->attachments[0]); + delete_fbo(shadow_buffer); } // TODO: compute better bounds based - const float factor = 10.0; - float left = res->player.model.geom.min[0] - factor; - float right = res->player.model.geom.max[0] + factor; - float bottom = res->player.model.geom.min[1] - factor; - float top = res->player.model.geom.max[1] + factor; + const float factor = 50.0; + float left = player->model.geom.min[0] - factor; + float right = player->model.geom.max[0] + factor; + float bottom = player->model.geom.min[1] - factor; + float top = player->model.geom.max[1] + factor; - const float near = -50.0; - const float far = 50.0; + const float near = -80.0; + const float far = 80.0; // default ortho screenspace projection - mat4_ortho(left, right, bottom, top, near, far, res->proj_ortho); + mat4_ortho(left, right, bottom, top, near, far, m4_ortho); - create_fbo(&res->shadow_buffer, width, height); + create_fbo(shadow_buffer, width, height ); /* fbo_attach_renderbuffer(&res->shadow_buffer, GL_DEPTH24_STENCIL8, */ /* GL_DEPTH_STENCIL_ATTACHMENT); */ /* fbo_attach_color_texture(&res->shadow_buffer); */ - fbo_attach_depth_texture(&res->shadow_buffer); + fbo_attach_depth_texture(shadow_buffer); - check_fbo(&res->shadow_buffer); + check_fbo(shadow_buffer); /* fbo_attach_texture(&res->shadow_buffer, GL_DEPTH_COMPONENT16, */ /* GL_DEPTH_COMPONENT, GL_DEPTH_ATTACHMENT); */ @@ -251,7 +249,7 @@ void resize_fbos(struct game *game, int width, int height) { static void day_night_cycle(float time, struct resources *res) { float val = time * 0.0001; float intensity = max(0.0, vec3_dot(res->light_dir, V3(0.0, 0.0, 0.8))); - struct entity *player = &res->player; + struct entity *player = get_player(res); float light_pos[3]; @@ -296,7 +294,7 @@ static void day_night_cycle(float time, struct resources *res) { } static void gravity(struct game *game) { - struct entity *player = &game->test_resources.player; + struct entity *player = get_player(&game->test_resources); node_translate(&player->node, V3(0.0, 0.0, -1.0)); } @@ -316,19 +314,21 @@ void update (struct game *game) { static int toggle_fog = 0; static int first = 1; struct resources *res = &game->test_resources; - struct node *tnode = &game->terrain.entity.node; + struct terrain *terrain = &game->terrain; + struct node *tnode = &get_entity(&terrain->entity_id)->node; struct node *root = &game->test_resources.root; + struct entity *player = get_player(res); float *time = &res->time; float *light = res->light_dir; gravity(game); if (first) { - update_terrain(game); + update_terrain(terrain); first = 0; } - player_update(game, &res->player); + player_update(game, player); if (game->input.modifiers & KMOD_LALT) { movement(game, &res->camera, 1.0); @@ -337,7 +337,7 @@ void update (struct game *game) { movement(game, tnode, 5.0); } else { - player_movement(game); + player_movement(game, player); } diff --git a/src/update.h b/src/update.h @@ -5,6 +5,7 @@ #include "game.h" void update(struct game * game); -void resize_fbos(struct game * game, int width, int height); +void resize_fbos(struct entity *player, struct fbo *shadow_buffer, + float *mat4_ortho, int width, int height); #endif /* PA_UPDATE_H */ diff --git a/src/window.c b/src/window.c @@ -14,7 +14,10 @@ handle_resize(struct game *game, int width, int height) { mat4_perspective(75 /* fov */, (float)width / height, 1, 20000, game->test_resources.proj_persp); - resize_fbos(game, width, height); + resize_fbos(get_entity(&game->test_resources.player_id), + &game->test_resources.shadow_buffer, + game->test_resources.proj_ortho, + width, height); /* glMatrixMode( GL_PROJECTION ); //Switch to setting the camera perspective */ /* Set the camera perspective */