diff --git a/src/game/bounding_volumes.c b/src/game/bounding_volumes.c index 2466138..5dfe39a 100755 --- a/src/game/bounding_volumes.c +++ b/src/game/bounding_volumes.c @@ -1,4 +1,5 @@ #include "bounding_volumes.h" +#include "../common/log.h" #include @@ -94,7 +95,7 @@ int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, v return intersect_type; } -bool bv_intersect_frustum_point(vec4* frustum, const vec3* point) +bool bv_point_inside_frustum(vec4* frustum, const vec3* point) { bool success = true; for(int i = 0; i < 6; i++) @@ -297,5 +298,78 @@ int bv_intersect_bounding_box_ray(struct Bounding_Box* box, struct Ray* ray) if(tzmax < tmax) tmax = tzmax; - return IT_INTERSECT; + return tmin < 0.f ? IT_INSIDE : IT_INTERSECT; +} + +float bv_distance_ray_bounding_box(struct Ray* ray, struct Bounding_Box* box) +{ + float tmin = (box->min.x - ray->origin.x) / ray->direction.x; + float tmax = (box->max.x - ray->origin.x) / ray->direction.x; + + if(tmin > tmax) + { + float temp = tmin; + tmin = tmax; + tmax = temp; + } + + float tymin = (box->min.y - ray->origin.y) / ray->direction.y; + float tymax = (box->max.y - ray->origin.y) / ray->direction.y; + + if(tymin > tymax) + { + float temp = tymin; + tymin = tymax; + tymax = temp; + } + + if((tmin > tymax) || (tymin > tmax)) + return INFINITY; + + if(tymin > tmin) + tmin = tymin; + + if(tymax < tmax) + tmax = tymax; + + float tzmin = (box->min.z - ray->origin.z) / ray->direction.z; + float tzmax = (box->max.z - ray->origin.z) / ray->direction.z; + + if(tzmin > tzmax) + { + float temp = tzmin; + tzmin = tzmax; + tzmax = temp; + } + + if((tmin > tzmax) || (tzmin > tmax)) + return INFINITY; + + if(tzmin > tmin) + tmin = tzmin; + + if(tzmax < tmax) + tmax = tzmax; + + return tmin >= 0.f ? tmin : tmax; // if tmin < 0, return the max value since it represents the hit in front of us. We don't care about hits behind us +} + +int bv_intersect_bounding_boxes(struct Bounding_Box* b1, struct Bounding_Box* b2) +{ + if(b2->max.x < b1->min.x || b2->min.x > b1->max.x || b2->max.y < b1->min.y || b2->min.y > b1->max.y || + b2->max.z < b1->min.z || b2->min.z > b1->max.z) + return IT_OUTSIDE; + else if(b2->min.x < b1->min.x || b2->max.x > b1->max.x || b2->min.y < b1->min.y || b2->max.y > b1->max.y || + b2->min.z < b1->min.z || b2->max.z > b1->max.z) + return IT_INTERSECT; + else + return IT_INSIDE; // b2 is inside b1 +} + +bool bv_point_inside_bounding_box(struct Bounding_Box* box, vec3 point) +{ + if(point.x < box->min.x || point.x > box->max.x || point.y < box->min.y || point.y > box->max.y || point.z < box->min.z || point.z > box->max.z) + return false; + else + return true; } diff --git a/src/game/bounding_volumes.h b/src/game/bounding_volumes.h index 393e622..dc816f9 100755 --- a/src/game/bounding_volumes.h +++ b/src/game/bounding_volumes.h @@ -52,11 +52,14 @@ struct Raycast_Result 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_sphere(vec4* frustum, struct Bounding_Sphere* sphere, vec3* sphere_abs_pos, vec3* sphere_abs_scale); -bool bv_intersect_frustum_point(vec4* frustum, const vec3* point); +bool bv_point_inside_frustum(vec4* frustum, const vec3* point); +bool bv_point_inside_bounding_box(struct Bounding_Box* box, vec3 point); int bv_intersect_bounding_box_ray(struct Bounding_Box* box, struct Ray* ray); int bv_intersect_sphere_ray(struct Bounding_Sphere* sphere, vec3* sphere_abs_position, vec3* sphere_abs_scale, struct Ray* ray); +int bv_intersect_bounding_boxes(struct Bounding_Box* b1, struct Bounding_Box* b2); float bv_distance_ray_plane(struct Ray* ray, Plane* plane); void bv_bounding_box_vertices_get(struct Bounding_Box* box, vec3 out_vertices[8]); void bv_bounding_box_vertices_get_line_visualization(struct Bounding_Box* bounding_box, vec3 out_vertices[24]); +float bv_distance_ray_bounding_box(struct Ray* ray, struct Bounding_Box* box); #endif diff --git a/src/game/editor.c b/src/game/editor.c index 97401a4..cd9e3bd 100755 --- a/src/game/editor.c +++ b/src/game/editor.c @@ -857,21 +857,11 @@ void editor_on_mousebutton_release(const struct Event* event) struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y); struct Scene* scene = game_state_get()->scene; - struct Raycast_Result ray_result; - scene_ray_intersect(scene, &ray, &ray_result); - - if(ray_result.num_entities_intersected > 0) + struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray); + if(intersected_entity) { - //For now, just select the first entity that is intersected - struct Entity* intersected_entity = ray_result.entities_intersected[0]; - if(intersected_entity == editor->cursor_entity) - { - if(ray_result.num_entities_intersected > 1) - intersected_entity = ray_result.entities_intersected[1]; - else - intersected_entity = NULL; - } - if(intersected_entity) editor_entity_select(editor, intersected_entity); + if(intersected_entity != editor->selected_entity) + editor_entity_select(editor, intersected_entity); } else { @@ -945,28 +935,12 @@ void editor_on_mousebutton_press(const struct Event* event) int mouse_x = 0, mouse_y = 0; platform_mouse_position_get(&mouse_x, &mouse_y); struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y); - - struct Raycast_Result ray_result; - scene_ray_intersect(scene, &ray, &ray_result); + struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray); bool start_rotation = true; - if(ray_result.num_entities_intersected > 0) + if(intersected_entity) { - //For now, just select the first entity that is intersected - struct Entity* intersected_entity = ray_result.entities_intersected[0]; - if(intersected_entity == editor->cursor_entity || intersected_entity == editor->selected_entity) - { - if(ray_result.num_entities_intersected > 1) - { - intersected_entity = ray_result.entities_intersected[1]; - if(intersected_entity) - { - editor_entity_select(editor, intersected_entity); - start_rotation = false; - } - } - } - else + if(intersected_entity != editor->selected_entity) { editor_entity_select(editor, intersected_entity); start_rotation = false; @@ -1166,13 +1140,24 @@ void editor_on_mousemotion(const struct Event* event) struct Scene* scene = game_state->scene; struct Camera* editor_camera = &scene->cameras[CAM_EDITOR]; struct Ray ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y); - struct Raycast_Result ray_result; - scene_ray_intersect(scene, &ray, &ray_result); - - if(ray_result.num_entities_intersected > 0) + //struct Raycast_Result ray_result; + //scene_ray_intersect(scene, &ray, &ray_result); + + //if(ray_result.num_entities_intersected > 0) + //{ + // struct Entity* intersected_entity = ray_result.entities_intersected[0]; + // if(intersected_entity && intersected_entity != editor->hovered_entity) + // editor->hovered_entity = intersected_entity; + //} + //else + //{ + // if(editor->hovered_entity) + // editor->hovered_entity = NULL; + //} + struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray); + if(intersected_entity) { - struct Entity* intersected_entity = ray_result.entities_intersected[0]; - if(intersected_entity && intersected_entity != editor->hovered_entity) + if(intersected_entity != editor->hovered_entity) editor->hovered_entity = intersected_entity; } else diff --git a/src/game/scene.c b/src/game/scene.c index 36bd547..3e39117 100755 --- a/src/game/scene.c +++ b/src/game/scene.c @@ -21,10 +21,10 @@ #include #include #include +#include static void scene_write_entity_entry(struct Scene* scene, struct Entity* entity, struct Parser* parser); static void scene_write_entity_list(struct Scene* scene, int entity_type, struct Parser* parser); -static int scene_sort_by_distance_from_active_viewer_func(const void* e1, const void* e2); void scene_init(struct Scene* scene) { @@ -821,32 +821,49 @@ void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Re transform_get_absolute_scale(mesh, &abs_scale); struct Geometry* geometry = geom_get(mesh->model.geometry_index); - //if(bv_intersect_sphere_ray(&geometry->bounding_sphere, &abs_pos, &abs_scale, ray) == IT_INTERSECT) if(bv_intersect_bounding_box_ray(&mesh->base.transform.bounding_box, ray) == IT_INTERSECT) { out_results->entities_intersected[out_results->num_entities_intersected] = &mesh->base; out_results->num_entities_intersected++; } } - - if(out_results->num_entities_intersected > 1) - qsort(out_results->entities_intersected, out_results->num_entities_intersected, sizeof(struct Entity*), &scene_sort_by_distance_from_active_viewer_func); } -int scene_sort_by_distance_from_active_viewer_func(const void* e1, const void* e2) +struct Entity* scene_ray_intersect_closest(struct Scene* scene, struct Ray* ray) { - const struct Entity* entity1 = *(struct Entity**)e1; - const struct Entity* entity2 = *(struct Entity**)e2; - struct Scene* scene = game_state_get()->scene; - struct Camera* camera = &scene->cameras[scene->active_camera_index]; - float d1 = scene_entity_distance(scene, entity1, camera); - float d2 = scene_entity_distance(scene, entity2, camera); - if(d1 < d2) - return -1; - else if(d1 == d2) - return 0; - else - return 1; + struct Entity* closest = NULL; + float current_closest = 0.f; + for(int i = 0; i < MAX_STATIC_MESHES; i++) + { + struct Static_Mesh* mesh = &scene->static_meshes[i]; + if(!(mesh->base.flags & EF_ACTIVE) || (mesh->base.flags & EF_IGNORE_RAYCAST)) continue; + vec3 abs_pos = { 0.f, 0.f, 0.f }; + vec3 abs_scale = { 1.f, 1.f, 1.f }; + transform_get_absolute_position(mesh, &abs_pos); + transform_get_absolute_scale(mesh, &abs_scale); + + struct Geometry* geometry = geom_get(mesh->model.geometry_index); + float distance = bv_distance_ray_bounding_box(ray, &mesh->base.transform.bounding_box); + if(distance != INFINITY && distance >= 0.f) + { + bool assign = false; + if(closest == NULL) + assign = true; + else if(distance > current_closest && + bv_intersect_bounding_box_ray(&mesh->base.transform.bounding_box, ray) == IT_INSIDE && + bv_intersect_bounding_boxes(&mesh->base.transform.bounding_box, &closest->transform.bounding_box) != IT_INSIDE) + assign = true; + else if(distance < current_closest) + assign = true; + + if(assign) + { + current_closest = distance; + closest = &mesh->base; + } + } + } + return closest; } float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2) diff --git a/src/game/scene.h b/src/game/scene.h index 3e47681..35c8433 100755 --- a/src/game/scene.h +++ b/src/game/scene.h @@ -60,8 +60,9 @@ void scene_entity_parent_set(struct Scene* scene, struct Entity* entity, struct void scene_entity_parent_reset(struct Scene* scene, struct Entity* entity); // Sets root entity as parent int scene_entity_archetype_add(struct Scene* scene, const char* filename); -void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Result* out_results); -float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2); +void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Result* out_results); +struct Entity* scene_ray_intersect_closest(struct Scene* scene, struct Ray* ray); +float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2); // //void scene_init(void); diff --git a/todo.txt b/todo.txt index ebc7e2d..6663194 100644 --- a/todo.txt +++ b/todo.txt @@ -1,9 +1,10 @@ Todo: + - Implement frustum culling with bounding boxes only or improve frustum-sphere intersection + - Imlpement picking entities of all types in editor - Determine whether we should enable or disble picking when a tool is active within an editor - - Implement checking if point is inside a bounding box and use that to determine whether a ray is originating inside a bounding box when checking for ray-boundingbox intersection - - Fix issue 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 + ? 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 - Command to create a placeholder entity of a particular type in a file - - Re-write/Overhaul bounding volumes and ray intersection - 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