diff --git a/src/common/linmath.c b/src/common/linmath.c index 6e30a87..bdbbcff 100755 --- a/src/common/linmath.c +++ b/src/common/linmath.c @@ -119,6 +119,13 @@ float vec3_len(vec3* val) return sqrtf((val->x * val->x) + (val->y * val->y) + (val->z * val->z)); } +float vec3_distance(vec3 p1, vec3 p2) +{ + vec3 v = { 0.f, 0.f, 0.f }; + vec3_sub(&v, &p1, &p2); + return vec3_len(&v); +} + void vec3_norm(vec3* res, vec3* val) { if(!val->x && !val->y && !val->z) diff --git a/src/common/linmath.h b/src/common/linmath.h index dda489f..b4b7c23 100755 --- a/src/common/linmath.h +++ b/src/common/linmath.h @@ -89,6 +89,7 @@ void vec3_scale(vec3* res, const vec3* val, float s); void vec3_transform_norm(vec3* res, const vec3* val, const mat4* mat); int vec3_equals(vec3* v1, vec3* v2); float vec3_len(vec3* val); +float vec3_distance(vec3 p1, vec3 p2); float vec3_dot(vec3* v1, vec3* v2); /* vec4 */ diff --git a/src/game/bounding_volumes.c b/src/game/bounding_volumes.c index 5dfe39a..0851b17 100755 --- a/src/game/bounding_volumes.c +++ b/src/game/bounding_volumes.c @@ -3,7 +3,7 @@ #include -int bv_intersect_frustum_box_(vec4* frustum, struct Bounding_Box* box) +int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box) { vec3 size, center, half_ext, half_size; vec3_fill(&size, 0.f, 0.f, 0.f); @@ -16,20 +16,38 @@ int bv_intersect_frustum_box_(vec4* frustum, struct Bounding_Box* box) vec3_scale(¢er, ¢er, 0.5f); vec3_assign(&half_ext, &size); vec3_scale(&half_size, &size, 0.5f); + //for(int i = 0; i < 6; i++) + //{ + // vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z}; + // float distance = frustum[i].w; + // float d = vec3_dot(&normal, ¢er); + // vec3 abs_normal = {fabsf(normal.x), fabsf(normal.y), fabsf(normal.z)}; + // float r = vec3_dot(&half_ext, &abs_normal); + // if(d + r < -distance) + // return IT_OUTSIDE; + //} + //return IT_INSIDE; + + vec3 edge = { 0.f, 0.f, 0.f }; + vec3_sub(&edge, ¢er, &box->min); + bool all_inside = true; for(int i = 0; i < 6; i++) { vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z}; - float distance = frustum[i].w; - float d = vec3_dot(&normal, ¢er); - vec3 abs_normal = {fabsf(normal.x), fabsf(normal.y), fabsf(normal.z)}; - float r = vec3_dot(&half_ext, &abs_normal); - if(d + r < -distance) + float d = frustum[i].w; + float dist = vec3_dot(&normal, ¢er) + d; + vec3 abs_normal = { fabsf(normal.x), fabsf(normal.y), fabsf(normal.z) }; + float abs_dist = vec3_dot(&abs_normal, &edge); + + if(dist < -abs_dist) return IT_OUTSIDE; + else if(dist < abs_dist) + all_inside = false; } - return IT_INSIDE; + return all_inside ? IT_INSIDE : IT_INTERSECT; } -int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale) +int bv_intersect_frustum_box_with_abs_transform(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale) { vec3 min, max, size, center, half_ext, half_size; vec3_fill(&min, 0.f, 0.f, 0.f); diff --git a/src/game/bounding_volumes.h b/src/game/bounding_volumes.h index dc816f9..81ab99e 100755 --- a/src/game/bounding_volumes.h +++ b/src/game/bounding_volumes.h @@ -49,8 +49,8 @@ struct Raycast_Result int num_entities_intersected; }; -int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale); -int bv_intersect_frustum_box_(vec4* frustum, struct Bounding_Box* box); +int bv_intersect_frustum_box_with_abs_transform(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale); +int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box); int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, vec3* sphere_abs_pos, vec3* sphere_abs_scale); bool bv_point_inside_frustum(vec4* frustum, const vec3* point); bool bv_point_inside_bounding_box(struct Bounding_Box* box, vec3 point); diff --git a/src/game/camera.c b/src/game/camera.c index fd22c10..a67d502 100755 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -198,9 +198,10 @@ static void update_frustum(struct Camera* camera) for(int i = 0; i < FP_NUM_PLANES; i++) { - vec3 plane_xyz = { camera->frustum[i].x, camera->frustum[i].y, camera->frustum[i].z }; - float length = fabsf(vec3_len(&plane_xyz)); - vec4_scale(&camera->frustum[i], &camera->frustum[i], (1.f / length)); + //vec3 plane_xyz = { camera->frustum[i].x, camera->frustum[i].y, camera->frustum[i].z }; + //float length = fabsf(vec3_len(&plane_xyz)); + //vec4_scale(&camera->frustum[i], &camera->frustum[i], (1.f / length)); + vec4_norm(&camera->frustum[i], &camera->frustum[i]); } } diff --git a/src/game/editor.c b/src/game/editor.c index cd9e3bd..68c9117 100755 --- a/src/game/editor.c +++ b/src/game/editor.c @@ -254,6 +254,25 @@ void editor_render(struct Editor* editor, struct Camera * active_camera) for(int i = 0; i <= 22; i += 2) im_line(vertices[i], vertices[i + 1], (vec3) { 0.f, 0.f, 0.f }, (quat) { 0.f, 0.f, 0.f, 1.f }, editor->cursor_entity_color, 3); + if(editor->selected_entity->type == ET_STATIC_MESH) + { + struct Static_Mesh* mesh = (struct Static_Mesh*)editor->selected_entity; + struct Geometry* geom = geom_get(mesh->model.geometry_index); + if(geom) + { + struct Bounding_Sphere* sphere = &geom->bounding_sphere; + vec3 abs_position = { 0.f, 0.f, 0.f }; + vec3 abs_scale = { 1.f, 1.f, 1.f }; + transform_get_absolute_position(editor->selected_entity, &abs_position); + transform_get_absolute_scale(editor->selected_entity, &abs_scale); + float max_scale = abs_scale.x; + if(abs_scale.y > max_scale) max_scale = abs_scale.y; + if(abs_scale.z > max_scale) max_scale = abs_scale.z; + //im_circle(sphere->radius * max_scale, 32, false, abs_position, (quat) { 0.f, 0.f, 0.f, 1.f }, editor->axis_color_x, 5); + im_circle(sphere->radius * max_scale, 32, false, abs_position, (quat) { 0.f, 0.f, 0.f, 1.f }, editor->axis_color_y, 5); + } + } + /* Draw selected entity with projected transformation applied */ if(editor->draw_cursor_entity) { diff --git a/src/game/geometry.c b/src/game/geometry.c index 1d6d1c1..f6b8db1 100755 --- a/src/game/geometry.c +++ b/src/game/geometry.c @@ -71,12 +71,18 @@ void geom_bounding_volume_generate(int index) if(vertex->y < box->min.y) box->min.y = vertex->y; if(vertex->z < box->min.z) box->min.z = vertex->z; } - vec3_sub(&sphere->center, &box->max, &box->min); + vec3_add(&sphere->center, &box->max, &box->min); vec3_scale(&sphere->center, &sphere->center, 0.5f); vec3 len_vec; - //vec3_sub(&len_vec, &box->max, &sphere->center); - //sphere->radius = fabsf(vec3_len(&len_vec)); - sphere->radius = fabsf(vec3_len(&sphere->center)); + vec3 box_vertices[8]; + bv_bounding_box_vertices_get(box, &box_vertices); + sphere->radius = 0.f; + for(int i = 0; i < 8; i++) + { + float len = fabsf(vec3_distance(box_vertices[i], sphere->center)); + if(len > sphere->radius) + sphere->radius = len; + } } void geom_bounding_volume_generate_all(void) @@ -376,7 +382,7 @@ int geom_render_in_frustum(int index, { //geom_render(index, draw_mode); //indices_rendered = array_len(geometry->indices); - intersection = bv_intersect_frustum_box(frustum, &geometry->bounding_box, &abs_pos, &abs_scale); + intersection = bv_intersect_frustum_box_with_abs_transform(frustum, &geometry->bounding_box, &abs_pos, &abs_scale); if(intersection == IT_INTERSECT || intersection == IT_INSIDE) { geom_render(index, draw_mode); diff --git a/src/game/renderer.c b/src/game/renderer.c index c581085..ded3129 100755 --- a/src/game/renderer.c +++ b/src/game/renderer.c @@ -256,29 +256,17 @@ void renderer_render(struct Renderer* renderer, struct Scene* scene) struct Geometry* geometry = geom_get(mesh->model.geometry_index); /* Check if model is in frustum */ - vec3 abs_pos, abs_scale; - transform_get_absolute_position(&mesh->base, &abs_pos); - transform_get_absolute_scale(&mesh->base, &abs_scale); - int intersection = bv_intersect_frustum_sphere(&camera->frustum[0], &geometry->bounding_sphere, &abs_pos, &abs_scale); - if(intersection == IT_OUTSIDE) + + int intersection = bv_intersect_frustum_box(&camera->frustum, &mesh->base.transform.bounding_box); + if(intersection == IT_INSIDE || intersection == IT_INTERSECT) { - renderer->num_culled++; - continue; + renderer->num_indices += array_len(geometry->indices); + renderer->num_rendered++; } else { - //intersection = bv_intersect_frustum_box(&camera->frustum, &geometry->bounding_box, &abs_pos, &abs_scale); - intersection = bv_intersect_frustum_box_(&camera->frustum, &mesh->base.transform.bounding_box); - if(intersection == IT_INSIDE || intersection == IT_INTERSECT) - { - renderer->num_indices += array_len(geometry->indices); - renderer->num_rendered++; - } - else - { - renderer->num_culled++; - continue; - } + renderer->num_culled++; + continue; } /* set material params for the model */ diff --git a/todo.txt b/todo.txt index 6663194..cfe8956 100644 --- a/todo.txt +++ b/todo.txt @@ -1,13 +1,16 @@ Todo: - - Implement frustum culling with bounding boxes only or improve frustum-sphere intersection + - Fix camera frustum creation/update - Imlpement picking entities of all types in editor - Determine whether we should enable or disble picking when a tool is active within an editor ? Only show bounding box for hovered entity - Fix crash where if an entity is hoverd in editor and deleted, the game crashes because the hovered variable in editor doesn't know that the entity was deleted + ? Write entity flags to scene file or when saving entity to file? + ? Add scene init/de-init function hashmap that maps a function that should be called when scene is loaded and unloaded. Save this to file for every scene or map functions based on the name of the scene? - Command to create a placeholder entity of a particular type in a file - Reduce the opacity of wireframe around selected entity in editor - Release mouse when window loses focus and limit fps - Allow picking and selecting other entity types in editor i.e. the ones that don't have meshes + ? Maybe reuse that same framebuffer/textures for active viewers ? When saving a scene entity entry, save the changed properties as well, that way when the scene is loaded, we load the base properties from archetype and the ones we changed per entry are saved when we saved the entity this will prevent us from having needless amount of entities with only minor changes from one another ? Split up material declarations into their own separate files. Materials have a base material like Blinn or Unshaded and in the file we save an instance with modified properties.