💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
25 KiB

/*
* Copyright (C) 2023 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/states/experiments/treadmill-experiment-state.hpp"
#include "game/ant/ant-cladogenesis.hpp"
#include "game/ant/ant-genome.hpp"
#include "game/ant/ant-morphogenesis.hpp"
#include "game/ant/ant-phenome.hpp"
#include "game/commands/commands.hpp"
#include "game/components/pose-component.hpp"
#include "game/components/constraint-stack-component.hpp"
#include "game/components/scene-component.hpp"
#include "game/components/picking-component.hpp"
#include "game/components/rigid-body-component.hpp"
#include "game/components/rigid-body-constraint-component.hpp"
#include "game/components/steering-component.hpp"
#include "game/components/terrain-component.hpp"
#include "game/components/navmesh-agent-component.hpp"
#include "game/components/legged-locomotion-component.hpp"
#include "game/components/winged-locomotion-component.hpp"
#include "game/components/ant-caste-component.hpp"
#include "game/components/ik-component.hpp"
#include "game/components/transform-component.hpp"
#include "game/components/ovary-component.hpp"
#include "game/components/spring-arm-component.hpp"
#include "game/components/ant-genome-component.hpp"
#include "game/constraints/child-of-constraint.hpp"
#include "game/constraints/copy-rotation-constraint.hpp"
#include "game/constraints/copy-scale-constraint.hpp"
#include "game/constraints/copy-transform-constraint.hpp"
#include "game/constraints/copy-translation-constraint.hpp"
#include "game/constraints/ease-to-constraint.hpp"
#include "game/constraints/pivot-constraint.hpp"
#include "game/constraints/spring-rotation-constraint.hpp"
#include "game/constraints/spring-to-constraint.hpp"
#include "game/constraints/spring-translation-constraint.hpp"
#include "game/constraints/three-dof-constraint.hpp"
#include "game/constraints/track-to-constraint.hpp"
#include "game/controls.hpp"
#include "game/spawn.hpp"
#include "game/states/pause-menu-state.hpp"
#include "game/systems/astronomy-system.hpp"
#include "game/systems/atmosphere-system.hpp"
#include "game/systems/camera-system.hpp"
#include "game/systems/collision-system.hpp"
#include "game/systems/physics-system.hpp"
#include "game/world.hpp"
#include <engine/animation/ease.hpp>
#include <engine/animation/screen-transition.hpp>
#include <engine/config.hpp>
#include <engine/entity/archetype.hpp>
#include <engine/input/mouse.hpp>
#include <engine/math/interpolation.hpp>
#include <engine/math/projection.hpp>
#include <engine/physics/light/exposure.hpp>
#include <engine/physics/kinematics/constraints/spring-constraint.hpp>
#include <engine/physics/kinematics/colliders/sphere-collider.hpp>
#include <engine/physics/kinematics/colliders/plane-collider.hpp>
#include <engine/physics/kinematics/colliders/box-collider.hpp>
#include <engine/physics/kinematics/colliders/capsule-collider.hpp>
#include <engine/physics/kinematics/colliders/mesh-collider.hpp>
#include <engine/render/passes/clear-pass.hpp>
#include <engine/render/passes/material-pass.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/state-machine.hpp>
#include <engine/scene/static-mesh.hpp>
#include <engine/scene/skeletal-mesh.hpp>
#include <engine/scene/rectangle-light.hpp>
#include <engine/scene/point-light.hpp>
#include <engine/geom/intersection.hpp>
#include <engine/animation/ease.hpp>
#include <engine/color/color.hpp>
#include <engine/geom/brep/brep-operations.hpp>
#include <engine/geom/coordinates.hpp>
#include <engine/ai/navmesh.hpp>
#include <engine/animation/ik/constraints/euler-ik-constraint.hpp>
treadmill_experiment_state::treadmill_experiment_state(::game& ctx):
game_state(ctx)
{
debug::log::trace("Entering nest view state...");
ctx.active_scene = ctx.surface_scene.get();
ctx.active_ecoregion = ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco");
::world::enter_ecoregion(ctx, *ctx.active_ecoregion);
debug::log::trace("Generating genome...");
std::shared_ptr<ant_genome> genome = ant_cladogenesis(ctx.active_ecoregion->gene_pools[0], ctx.rng);
debug::log::trace("Generated genome");
debug::log::trace("Building worker phenome...");
worker_phenome = std::make_shared<ant_phenome>(*genome, ant_caste_type::worker);
debug::log::trace("Built worker phenome...");
debug::log::trace("Generating worker model...");
std::shared_ptr<render::model> worker_model = ant_morphogenesis(*worker_phenome);
debug::log::trace("Generated worker model");
// Create directional light
// ctx.underground_directional_light = std::make_unique<scene::directional_light>();
// ctx.underground_directional_light->set_color({1.0f, 1.0f, 1.0f});
// ctx.underground_directional_light->set_illuminance(2.0f);
// ctx.underground_directional_light->set_direction(math::normalize(math::fvec3{0, -1, 0}));
// ctx.underground_directional_light->set_shadow_caster(true);
// ctx.underground_directional_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer);
// ctx.underground_directional_light->set_shadow_bias(0.005f);
// ctx.underground_directional_light->set_shadow_cascade_count(4);
// ctx.underground_directional_light->set_shadow_cascade_coverage(0.15f);
// ctx.underground_directional_light->set_shadow_cascade_distribution(0.8f);
// ctx.underground_scene->add_object(*ctx.underground_directional_light);
// ctx.underground_clear_pass->set_clear_color({0.214f, 0.214f, 0.214f, 1.0f});
// ctx.underground_clear_pass->set_clear_color({});
// light_probe = std::make_shared<scene::light_probe>();
// light_probe->set_luminance_texture(ctx.resource_manager->load<gl::texture_cube>("grey-furnace.tex"));
// ctx.underground_scene->add_object(*light_probe);
//const float color_temperature = 5000.0f;
//const math::fvec3 light_color = color::aces::ap1<float>.from_xyz * color::cat::matrix(color::illuminant::deg2::d50<float>, color::aces::white_point<float>) * color::cct::to_xyz(color_temperature);
// const math::fvec3 light_color{1.0f, 1.0f, 1.0f};
// Create rectangle light
// ctx.underground_rectangle_light = std::make_unique<scene::rectangle_light>();
// ctx.underground_rectangle_light->set_color(light_color);
// ctx.underground_rectangle_light->set_luminous_flux(1500.0f);
// ctx.underground_rectangle_light->set_translation({0.0f, 10.0f, 0.0f});
// ctx.underground_rectangle_light->set_rotation(math::fquat::rotate_x(math::radians(90.0f)));
// ctx.underground_rectangle_light->set_scale(7.0f);
// ctx.underground_scene->add_object(*ctx.underground_rectangle_light);
// Create light rectangle
// auto light_rectangle_model = ctx.resource_manager->load<render::model>("light-rectangle.mdl");
// auto light_rectangle_material = std::make_shared<render::material>(*light_rectangle_model->get_groups().front().material);
// light_rectangle_emissive = std::static_pointer_cast<render::matvar_fvec3>(light_rectangle_material->get_variable("emissive"));
// light_rectangle_emissive->set(ctx.underground_rectangle_light->get_colored_luminance());
// auto light_rectangle_static_mesh = std::make_shared<scene::static_mesh>(light_rectangle_model);
// light_rectangle_static_mesh->set_material(0, light_rectangle_material);
// auto light_rectangle_eid = ctx.entity_registry->create();
// ctx.entity_registry->emplace<scene_component>(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{1});
// ctx.entity_registry->patch<scene_component>
// (
// light_rectangle_eid,
// [&](auto& component)
// {
// component.object->set_transform(ctx.underground_rectangle_light->get_transform());
// }
// );
// Create nest exterior
// {
// scene_component nest_exterior_scene_component;
// nest_exterior_scene_component.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("round-petri-dish-nest-100mm-exterior.mdl"));
// nest_exterior_scene_component.layer_mask = 1;
// auto nest_exterior_eid = ctx.entity_registry->create();
// ctx.entity_registry->emplace<scene_component>(nest_exterior_eid, std::move(nest_exterior_scene_component));
// }
// Create nest exterior
{
scene_component nest_exterior_scene_component;
nest_exterior_scene_component.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere-nest-100mm-exterior.mdl"));
nest_exterior_scene_component.layer_mask = 1;
auto nest_exterior_mesh = ctx.resource_manager->load<geom::brep_mesh>("sphere-nest-100mm-exterior.msh");
auto nest_exterior_rigid_body = std::make_unique<physics::rigid_body>();
nest_exterior_rigid_body->set_mass(0.0f);
nest_exterior_rigid_body->set_collider(std::make_shared<physics::mesh_collider>(std::move(nest_exterior_mesh)));
auto nest_exterior_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(nest_exterior_eid, std::move(nest_exterior_scene_component));
ctx.entity_registry->emplace<rigid_body_component>(nest_exterior_eid, std::move(nest_exterior_rigid_body));
}
// Create nest interior
{
scene_component nest_interior_scene_component;
nest_interior_scene_component.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("sphere-nest-100mm-interior.mdl"));
nest_interior_scene_component.object->set_layer_mask(0b10);
nest_interior_scene_component.layer_mask = 1;
auto nest_interior_mesh = ctx.resource_manager->load<geom::brep_mesh>("sphere-nest-100mm-interior.msh");
auto nest_interior_rigid_body = std::make_unique<physics::rigid_body>();
nest_interior_rigid_body->set_mass(0.0f);
nest_interior_rigid_body->set_collider(std::make_shared<physics::mesh_collider>(std::move(nest_interior_mesh)));
nest_interior_rigid_body->get_collider()->set_layer_mask(0b10);
auto nest_interior_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(nest_interior_eid, std::move(nest_interior_scene_component));
ctx.entity_registry->emplace<rigid_body_component>(nest_interior_eid, std::move(nest_interior_rigid_body));
}
// Create rectangle light
{
area_light = std::make_unique<scene::rectangle_light>();
area_light->set_luminous_flux(5000000.0f);
area_light->set_translation({0.0f, 0.0f, 0.0f});
area_light->set_rotation(math::fquat::rotate_x(math::radians(90.0f)));
area_light->set_scale(5.0f);
area_light->set_layer_mask(0b10);
ctx.surface_scene->add_object(*area_light);
// Create light rectangle
auto light_rectangle_model = ctx.resource_manager->load<render::model>("light-rectangle.mdl");
auto light_rectangle_material = std::make_shared<render::material>(*light_rectangle_model->get_groups().front().material);
light_rectangle_emissive = std::static_pointer_cast<render::matvar_fvec3>(light_rectangle_material->get_variable("emissive"));
light_rectangle_emissive->set(area_light->get_colored_luminance());
auto light_rectangle_static_mesh = std::make_shared<scene::static_mesh>(light_rectangle_model);
light_rectangle_static_mesh->set_material(0, light_rectangle_material);
light_rectangle_static_mesh->set_transform(area_light->get_transform());
light_rectangle_static_mesh->set_layer_mask(area_light->get_layer_mask());
auto light_rectangle_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(light_rectangle_eid, std::move(light_rectangle_static_mesh), std::uint8_t{1});
}
// Create worker
auto worker_skeletal_mesh = std::make_unique<scene::skeletal_mesh>(worker_model);
worker_skeletal_mesh->set_layer_mask(0b11);
// Create worker IK rig
const auto& worker_skeleton = worker_model->get_skeleton();
worker_ik_rig = std::make_shared<ik_rig>(*worker_skeletal_mesh);
auto mesocoxa_ik_constraint = std::make_shared<euler_ik_constraint>();
mesocoxa_ik_constraint->set_min_angles({-math::pi<float>, -math::pi<float>, -math::pi<float>});
mesocoxa_ik_constraint->set_max_angles({ math::pi<float>, math::pi<float>, math::pi<float>});
worker_ik_rig->set_constraint(*worker_skeleton.get_bone_index("mesocoxa_l"), std::move(mesocoxa_ik_constraint));
// Pose worker
worker_skeletal_mesh->get_pose() = *worker_model->get_skeleton().get_pose("midswing");
worker_eid = ctx.entity_registry->create();
pose_component worker_pose_component;
worker_pose_component.current_pose = worker_skeletal_mesh->get_skeleton()->get_rest_pose();
worker_pose_component.previous_pose = worker_pose_component.current_pose;
ant_caste_component worker_caste_component;
worker_caste_component.type = ant_caste_type::worker;
worker_caste_component.phenome = worker_phenome;
rigid_body_component worker_rigid_body_component;
worker_rigid_body_component.body = std::make_unique<physics::rigid_body>();
worker_rigid_body_component.body->set_mass(0.0f);
auto rigid_body_transform = worker_rigid_body_component.body->get_transform();
rigid_body_transform.scale = math::fvec3::one() * worker_phenome->body_size->mean_mesosoma_length;
worker_rigid_body_component.body->set_transform(rigid_body_transform);
legged_locomotion_component worker_locomotion_component;
worker_locomotion_component.midstance_pose = worker_model->get_skeleton().get_pose("midstance");
worker_locomotion_component.midswing_pose = worker_model->get_skeleton().get_pose("midswing");
worker_locomotion_component.liftoff_pose = worker_model->get_skeleton().get_pose("liftoff");
worker_locomotion_component.touchdown_pose = worker_model->get_skeleton().get_pose("touchdown");
worker_locomotion_component.body_bone = *worker_skeleton.get_bone_index("mesosoma");
worker_locomotion_component.tip_bones =
{
*worker_skeleton.get_bone_index("protarsomere1_l"),
*worker_skeleton.get_bone_index("mesotarsomere1_l"),
*worker_skeleton.get_bone_index("metatarsomere1_l"),
*worker_skeleton.get_bone_index("protarsomere1_r"),
*worker_skeleton.get_bone_index("mesotarsomere1_r"),
*worker_skeleton.get_bone_index("metatarsomere1_r")
};
worker_locomotion_component.leg_bone_count = 4;
worker_locomotion_component.gait = std::make_shared<::gait>();
worker_locomotion_component.gait->frequency = 4.0f;
worker_locomotion_component.gait->steps.resize(6);
for (std::size_t i = 0; i < 6; ++i)
{
const float duty_factors[3] = {0.52f, 0.62f, 0.54f};
auto& step = worker_locomotion_component.gait->steps[i];
step.duty_factor = duty_factors[i % 3];
step.delay = (i % 2) ? 0.5f : 0.0f;
}
worker_locomotion_component.standing_height = worker_phenome->legs->standing_height;
worker_locomotion_component.stride_length = worker_phenome->legs->stride_length * worker_rigid_body_component.body->get_transform().scale.x();
worker_locomotion_component.max_angular_frequency = worker_phenome->legs->max_angular_frequency;
navmesh_agent_component worker_navmesh_agent_component;
ovary_component worker_ovary_component;
worker_ovary_component.egg_capacity = 4;
worker_ovary_component.egg_production_duration = 1.0f;
worker_ovary_component.oviposition_duration = 3.0f;
worker_ovary_component.ovipositor_bone = *worker_skeleton.get_bone_index("gaster");
worker_ovary_component.oviposition_path = {{0.0f, -0.141708f, -0.799793f}, {0.0f, -0.187388f, -1.02008f}};
ctx.entity_registry->emplace<scene_component>(worker_eid, std::move(worker_skeletal_mesh), std::uint8_t{1});
ctx.entity_registry->emplace<navmesh_agent_component>(worker_eid, std::move(worker_navmesh_agent_component));
ctx.entity_registry->emplace<pose_component>(worker_eid, std::move(worker_pose_component));
ctx.entity_registry->emplace<legged_locomotion_component>(worker_eid, std::move(worker_locomotion_component));
ctx.entity_registry->emplace<ant_caste_component>(worker_eid, std::move(worker_caste_component));
ctx.entity_registry->emplace<rigid_body_component>(worker_eid, std::move(worker_rigid_body_component));
ctx.entity_registry->emplace<ovary_component>(worker_eid, std::move(worker_ovary_component));
ctx.entity_registry->emplace<ant_genome_component>(worker_eid, genome);
// Set ant as controlled ant
ctx.controlled_ant_eid = worker_eid;
// Create color checker
auto color_checker_eid = ctx.entity_registry->create();
scene_component color_checker_scene_component;
color_checker_scene_component.object = std::make_shared<scene::static_mesh>(ctx.resource_manager->load<render::model>("color-checker.mdl"));
color_checker_scene_component.object->set_translation({0, 0, 4});
color_checker_scene_component.layer_mask = 1;
ctx.entity_registry->emplace<scene_component>(color_checker_eid, std::move(color_checker_scene_component));
// Disable UI color clear
ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
// Set world time
::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
// Init time scale
double time_scale = 0.0;
// Set time scale
::world::set_time_scale(ctx, time_scale);
// Setup and enable sky and ground passes
ctx.sky_pass->set_enabled(true);
sky_probe = std::make_shared<scene::light_probe>();
sky_probe->set_luminance_texture(std::make_shared<gl::texture_cube>(512, 384, gl::pixel_type::float_16, gl::pixel_format::rgb));
ctx.sky_pass->set_sky_probe(sky_probe);
ctx.surface_scene->add_object(*sky_probe);
// Set camera exposure
const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
ctx.surface_camera->set_exposure_value(ev100_sunny16);
const auto& viewport_size = ctx.window->get_viewport_size();
const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
// Create third person camera rig
create_third_person_camera_rig();
// Setup controls
setup_controls();
// Queue enable game controls
ctx.function_queue.push
(
[&ctx]()
{
::enable_game_controls(ctx);
::enable_camera_controls(ctx);
::enable_ant_controls(ctx);
}
);
// Queue fade in
ctx.fade_transition_color->set({0, 0, 0});
ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition.get(), 1.0f, true, ease<float>::out_sine, true, nullptr));
// Refresh frame scheduler
ctx.frame_scheduler.refresh();
debug::log::trace("Entered nest view state");
}
treadmill_experiment_state::~treadmill_experiment_state()
{
debug::log::trace("Exiting nest view state...");
// Disable game controls
::disable_game_controls(ctx);
::disable_camera_controls(ctx);
::disable_ant_controls(ctx);
ctx.controlled_ant_eid = entt::null;
destroy_third_person_camera_rig();
debug::log::trace("Exited nest view state");
}
void treadmill_experiment_state::create_third_person_camera_rig()
{
const auto& subject_rigid_body = *ctx.entity_registry->get<rigid_body_component>(ctx.controlled_ant_eid).body;
const auto subject_scale = static_cast<double>(subject_rigid_body.get_transform().scale.x());
spring_arm_component spring_arm;
spring_arm.parent_eid = ctx.controlled_ant_eid;
spring_arm.near_focal_plane_height = 8.0 * subject_scale;
spring_arm.far_focal_plane_height = 80.0 * subject_scale;
spring_arm.near_hfov = math::radians(90.0);
spring_arm.far_hfov = math::radians(45.0);
// spring_arm.far_hfov = math::radians(90.0);
spring_arm.zoom = 0.25;
spring_arm.focal_point_offset = {0, static_cast<double>(worker_phenome->legs->standing_height) * subject_scale, 0};
spring_arm.focal_point_spring.set_damping_ratio(1.0);
spring_arm.focal_point_spring.set_period(0.01);
spring_arm.angles_spring.set_damping_ratio(1.0);
spring_arm.angles_spring.set_period(0.25);
spring_arm.min_angles.x() = -math::half_pi<double>;
spring_arm.max_angles.x() = 0.0;
third_person_camera_rig_eid = ctx.entity_registry->create();
ctx.entity_registry->emplace<scene_component>(third_person_camera_rig_eid, ctx.surface_camera, std::uint8_t{1});
ctx.entity_registry->emplace<spring_arm_component>(third_person_camera_rig_eid, std::move(spring_arm));
ctx.active_camera_eid = third_person_camera_rig_eid;
}
void treadmill_experiment_state::destroy_third_person_camera_rig()
{
ctx.entity_registry->destroy(third_person_camera_rig_eid);
}
void treadmill_experiment_state::set_third_person_camera_zoom(double zoom)
{
}
void treadmill_experiment_state::set_third_person_camera_rotation(double yaw, double pitch)
{
}
void treadmill_experiment_state::zoom_third_person_camera(double zoom)
{
}
void treadmill_experiment_state::translate_third_person_camera(const math::dvec3& direction, double magnitude)
{
}
void treadmill_experiment_state::rotate_third_person_camera(const input::mouse_moved_event& event)
{
}
void treadmill_experiment_state::handle_mouse_motion(const input::mouse_moved_event& event)
{
ctx.surface_material_pass->set_mouse_position(math::fvec2(event.position));
if (!mouse_look && !mouse_grip && !mouse_zoom)
{
return;
}
if (mouse_grip)
{
const math::dvec2 viewport_size = math::dvec2(ctx.window->get_viewport_size());
math::dvec3 translation
{
third_person_camera_focal_plane_width * (static_cast<double>(-event.difference.x()) / (viewport_size.x() - 1.0)),
0.0,
third_person_camera_focal_plane_height * (static_cast<double>(-event.difference.y()) / (viewport_size.y() - 1.0)),
};
if (third_person_camera_pitch < 0.0)
{
translation.z() *= -1.0;
}
third_person_camera_focal_point += third_person_camera_yaw_rotation * translation;
}
if (mouse_look)
{
rotate_third_person_camera(event);
}
if (mouse_zoom)
{
const double zoom_speed = -1.0 / static_cast<double>(ctx.window->get_viewport_size().y());
zoom_third_person_camera(static_cast<double>(event.difference.y()) * zoom_speed);
}
update_third_person_camera();
}
void treadmill_experiment_state::update_third_person_camera()
{
}
void treadmill_experiment_state::load_camera_preset(std::uint8_t index)
{
}
void treadmill_experiment_state::save_camera_preset(std::uint8_t index)
{
}
void treadmill_experiment_state::load_or_save_camera_preset(std::uint8_t index)
{
}
geom::ray<float, 3> treadmill_experiment_state::get_mouse_ray(const math::vec2<std::int32_t>& mouse_position) const
{
// Get window viewport size
const auto& viewport_size = ctx.window->get_viewport_size();
// Transform mouse coordinates from window space to NDC space
const math::fvec2 mouse_ndc =
{
static_cast<float>(mouse_position.x()) / static_cast<float>(viewport_size.x() - 1) * 2.0f - 1.0f,
(1.0f - static_cast<float>(mouse_position.y()) / static_cast<float>(viewport_size.y() - 1)) * 2.0f - 1.0f
};
const auto& scene_component = ctx.entity_registry->get<::scene_component>(third_person_camera_rig_eid);
const auto& camera = static_cast<const scene::camera&>(*scene_component.object);
return camera.pick(mouse_ndc);
}
void treadmill_experiment_state::setup_controls()
{
// Enable/toggle mouse grip
action_subscriptions.emplace_back
(
ctx.camera_mouse_pick_action.get_activated_channel().subscribe
(
[&](const auto& event)
{
mouse_grip = ctx.toggle_mouse_grip ? !mouse_grip : true;
if (mouse_grip)
{
const auto& mouse_position = (*ctx.input_manager->get_mice().begin())->get_position();
// Cast ray to plane
const auto mouse_ray = get_mouse_ray(mouse_position);
const auto intersection = geom::intersection(mouse_ray, mouse_grip_plane);
if (intersection)
{
mouse_grip_point = mouse_ray.origin + mouse_ray.direction * (*intersection);
}
}
// BVH picking test
const auto& mouse_position = (*ctx.input_manager->get_mice().begin())->get_position();
const auto mouse_ray = get_mouse_ray(mouse_position);
const auto& camera_object = *ctx.entity_registry->get<::scene_component>(ctx.active_camera_eid).object;
if (auto trace = ctx.physics_system->trace(mouse_ray, entt::null, camera_object.get_layer_mask()))
{
// debug::log::debug("HIT! EID: {}; distance: {}; face: {}", static_cast<int>(std::get<0>(*trace)), std::get<1>(*trace), std::get<2>(*trace));
const auto& hit_rigid_body = *ctx.entity_registry->get<rigid_body_component>(std::get<0>(*trace)).body;
const auto& hit_collider = *hit_rigid_body.get_collider();
const auto hit_distance = std::get<1>(*trace);
const auto& hit_normal = std::get<3>(*trace);
geom::brep_mesh* hit_mesh = nullptr;
geom::brep_face* hit_face = nullptr;
if (hit_collider.type() == physics::collider_type::mesh)
{
hit_mesh = static_cast<const physics::mesh_collider&>(hit_collider).get_mesh().get();
hit_face = hit_mesh->faces()[std::get<2>(*trace)];
}
// Update agent transform
auto& agent_rigid_body = *ctx.entity_registry->get<rigid_body_component>(worker_eid).body;
auto agent_transform = agent_rigid_body.get_transform();
agent_transform.translation = mouse_ray.extrapolate(hit_distance);
agent_transform.rotation = math::rotation(math::fvec3{0, 1, 0}, hit_normal);
agent_rigid_body.set_transform(agent_transform);
agent_rigid_body.set_previous_transform(agent_transform);
// Update agent navmesh
ctx.entity_registry->patch<navmesh_agent_component>
(
worker_eid,
[&](auto& component)
{
component.mesh = hit_mesh;
component.face = hit_face;
component.surface_normal = hit_normal;
}
);
}
}
)
);
}