Browse Source

Improve placement system and rename to snapping system, add spring constraint structure and helper function, improve camera easing via spring constraints

master
C. J. Howard 3 years ago
parent
commit
db9b09ac98
17 changed files with 317 additions and 124 deletions
  1. +33
    -0
      src/animation/spring.hpp
  2. +5
    -0
      src/application.cpp
  3. +2
    -0
      src/application.hpp
  4. +9
    -5
      src/game/bootloader.cpp
  5. +7
    -4
      src/game/components/snap-component.hpp
  6. +9
    -0
      src/game/entity-commands.cpp
  7. +1
    -0
      src/game/entity-commands.hpp
  8. +3
    -2
      src/game/game-context.hpp
  9. +31
    -10
      src/game/states/play-state.cpp
  10. +2
    -0
      src/game/states/splash-state.cpp
  11. +69
    -41
      src/game/systems/camera-system.cpp
  12. +20
    -0
      src/game/systems/camera-system.hpp
  13. +85
    -39
      src/game/systems/control-system.cpp
  14. +9
    -1
      src/game/systems/control-system.hpp
  15. +26
    -16
      src/game/systems/snapping-system.cpp
  16. +5
    -5
      src/game/systems/snapping-system.hpp
  17. +1
    -1
      src/game/systems/vegetation-system.cpp

+ 33
- 0
src/animation/spring.hpp View File

@ -20,6 +20,24 @@
#ifndef ANTKEEPER_SPRING_HPP #ifndef ANTKEEPER_SPRING_HPP
#define ANTKEEPER_SPRING_HPP #define ANTKEEPER_SPRING_HPP
/**
* Contains the variables required for numeric springing.
*
* @tparam T Value type.
* @tparam S Scalar type.
*
* @see spring()
*/
template <typename T, typename S>
struct spring_constraint
{
T x0; ///< Start value
T x1; ///< End value
T v; ///< Velocity
S z; ///< Damping ratio, which can be undamped (z = 0), underdamped (z < 1), critically damped (z = 1), or overdamped (z > 1).
S w; ///< Angular frequency of the oscillation, in radians per second (2pi = 1Hz).
};
/** /**
* Performs numeric, damped springing on a value and velocity. * Performs numeric, damped springing on a value and velocity.
* *
@ -36,6 +54,15 @@
template <typename T, typename S> template <typename T, typename S>
void spring(T& x0, T& v, const T& x1, S z, S w, S dt); void spring(T& x0, T& v, const T& x1, S z, S w, S dt);
/**
* Solves a spring constraint using the spring() function.
*
* @param[in,out] constraint Spring constraint to be sovled.
* @param dt Delta time, in seconds.
*/
template <typename T, typename S>
void solve_spring_constraint(spring_constraint<T, S>& constraint, S dt);
template <typename T, typename S> template <typename T, typename S>
void spring(T& x0, T& v, const T& x1, S z, S w, S dt) void spring(T& x0, T& v, const T& x1, S z, S w, S dt)
{ {
@ -50,4 +77,10 @@ void spring(T& x0, T& v, const T& x1, S z, S w, S dt)
v = det_v * inv_det; v = det_v * inv_det;
} }
template <typename T, typename S>
void solve_spring_constraint(spring_constraint<T, S>& constraint, S dt)
{
spring(constraint.x0, constraint.v, constraint.x1, constraint.z, constraint.w, dt);
}
#endif // ANTKEEPER_SPRING_HPP #endif // ANTKEEPER_SPRING_HPP

+ 5
- 0
src/application.cpp View File

@ -417,6 +417,11 @@ void application::set_vsync(bool vsync)
} }
} }
void application::set_window_opacity(float opacity)
{
SDL_SetWindowOpacity(sdl_window, opacity);
}
void application::update(double t, double dt) void application::update(double t, double dt)
{ {
translate_sdl_events(); translate_sdl_events();

+ 2
- 0
src/application.hpp View File

@ -159,6 +159,8 @@ public:
*/ */
void set_vsync(bool vsync); void set_vsync(bool vsync);
void set_window_opacity(float opacity);
/// Returns the dimensions of the current display. /// Returns the dimensions of the current display.
const std::array<int, 2>& get_display_dimensions() const; const std::array<int, 2>& get_display_dimensions() const;

+ 9
- 5
src/game/bootloader.cpp View File

@ -66,7 +66,7 @@
#include "game/systems/control-system.hpp" #include "game/systems/control-system.hpp"
#include "game/systems/locomotion-system.hpp" #include "game/systems/locomotion-system.hpp"
#include "game/systems/nest-system.hpp" #include "game/systems/nest-system.hpp"
#include "game/systems/placement-system.hpp"
#include "game/systems/snapping-system.hpp"
#include "game/systems/render-system.hpp" #include "game/systems/render-system.hpp"
#include "game/systems/samara-system.hpp" #include "game/systems/samara-system.hpp"
#include "game/systems/subterrain-system.hpp" #include "game/systems/subterrain-system.hpp"
@ -747,6 +747,7 @@ void setup_entities(game_context* ctx)
ctx->flashlight_entity = ctx->ecs_registry->create(); ctx->flashlight_entity = ctx->ecs_registry->create();
ctx->forceps_entity = ctx->ecs_registry->create(); ctx->forceps_entity = ctx->ecs_registry->create();
ctx->lens_entity = ctx->ecs_registry->create(); ctx->lens_entity = ctx->ecs_registry->create();
ctx->focal_point_entity = ctx->ecs_registry->create();
} }
void setup_systems(game_context* ctx) void setup_systems(game_context* ctx)
@ -792,8 +793,8 @@ void setup_systems(game_context* ctx)
// Setup samara system // Setup samara system
ctx->samara_system = new samara_system(*ctx->ecs_registry); ctx->samara_system = new samara_system(*ctx->ecs_registry);
// Setup placement system
ctx->placement_system = new placement_system(*ctx->ecs_registry);
// Setup snapping system
ctx->snapping_system = new snapping_system(*ctx->ecs_registry);
// Setup behavior system // Setup behavior system
ctx->behavior_system = new behavior_system(*ctx->ecs_registry); ctx->behavior_system = new behavior_system(*ctx->ecs_registry);
@ -829,6 +830,8 @@ void setup_systems(game_context* ctx)
ctx->control_system->get_adjust_camera_control()->set_activated_callback([ctx](){ ctx->app->set_relative_mouse_mode(true); ctx->tool_system->set_pick(false); }); ctx->control_system->get_adjust_camera_control()->set_activated_callback([ctx](){ ctx->app->set_relative_mouse_mode(true); ctx->tool_system->set_pick(false); });
ctx->control_system->get_adjust_camera_control()->set_deactivated_callback([ctx](){ ctx->app->set_relative_mouse_mode(false); ctx->tool_system->set_pick(true); }); ctx->control_system->get_adjust_camera_control()->set_deactivated_callback([ctx](){ ctx->app->set_relative_mouse_mode(false); ctx->tool_system->set_pick(true); });
ctx->control_system->set_flashlight(ctx->flashlight_entity); ctx->control_system->set_flashlight(ctx->flashlight_entity);
ctx->control_system->set_camera_subject(ctx->focal_point_entity);
ctx->control_system->set_camera_system(ctx->camera_system);
// Setup UI system // Setup UI system
ctx->ui_system = new ui_system(ctx->resource_manager); ctx->ui_system = new ui_system(ctx->resource_manager);
@ -997,6 +1000,7 @@ void setup_controls(game_context* ctx)
ctx->input_event_router->add_mapping(game_controller_axis_mapping(ctx->control_system->get_zoom_in_control(), nullptr, game_controller_axis::trigger_right, false)); ctx->input_event_router->add_mapping(game_controller_axis_mapping(ctx->control_system->get_zoom_in_control(), nullptr, game_controller_axis::trigger_right, false));
event_dispatcher->subscribe<mouse_moved_event>(ctx->control_system); event_dispatcher->subscribe<mouse_moved_event>(ctx->control_system);
event_dispatcher->subscribe<window_resized_event>(ctx->control_system);
event_dispatcher->subscribe<mouse_moved_event>(ctx->camera_system); event_dispatcher->subscribe<mouse_moved_event>(ctx->camera_system);
event_dispatcher->subscribe<window_resized_event>(ctx->camera_system); event_dispatcher->subscribe<window_resized_event>(ctx->camera_system);
event_dispatcher->subscribe<mouse_moved_event>(ctx->tool_system); event_dispatcher->subscribe<mouse_moved_event>(ctx->tool_system);
@ -1032,10 +1036,10 @@ void setup_callbacks(game_context* ctx)
ctx->timeline->advance(dt); ctx->timeline->advance(dt);
//ctx->control_system->update(t, dt);
ctx->control_system->update(t, dt);
ctx->terrain_system->update(t, dt); ctx->terrain_system->update(t, dt);
ctx->vegetation_system->update(t, dt); ctx->vegetation_system->update(t, dt);
ctx->placement_system->update(t, dt);
ctx->snapping_system->update(t, dt);
ctx->nest_system->update(t, dt); ctx->nest_system->update(t, dt);
ctx->subterrain_system->update(t, dt); ctx->subterrain_system->update(t, dt);
ctx->collision_system->update(t, dt); ctx->collision_system->update(t, dt);

src/game/components/placement-component.hpp → src/game/components/snap-component.hpp View File

@ -17,19 +17,22 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP
#define ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP
#ifndef ANTKEEPER_ECS_SNAP_COMPONENT_HPP
#define ANTKEEPER_ECS_SNAP_COMPONENT_HPP
#include "geometry/ray.hpp" #include "geometry/ray.hpp"
namespace ecs { namespace ecs {
struct placement_component
struct snap_component
{ {
::ray<float> ray; ::ray<float> ray;
bool relative;
bool warp;
bool autoremove;
}; };
} // namespace ecs } // namespace ecs
#endif // ANTKEEPER_ECS_PLACEMENT_COMPONENT_HPP
#endif // ANTKEEPER_ECS_SNAP_COMPONENT_HPP

+ 9
- 0
src/game/entity-commands.cpp View File

@ -26,6 +26,15 @@ namespace ec {
using namespace ecs; using namespace ecs;
void translate(entt::registry& registry, entt::entity eid, const float3& translation)
{
if (registry.has<transform_component>(eid))
{
transform_component& transform = registry.get<transform_component>(eid);
transform.transform.translation += translation;
}
}
void move_to(entt::registry& registry, entt::entity eid, const float3& position) void move_to(entt::registry& registry, entt::entity eid, const float3& position)
{ {
if (registry.has<transform_component>(eid)) if (registry.has<transform_component>(eid))

+ 1
- 0
src/game/entity-commands.hpp View File

@ -26,6 +26,7 @@
namespace ec { namespace ec {
void translate(entt::registry& registry, entt::entity eid, const float3& translation);
void move_to(entt::registry& registry, entt::entity eid, const float3& position); void move_to(entt::registry& registry, entt::entity eid, const float3& position);
void warp_to(entt::registry& registry, entt::entity eid, const float3& position); void warp_to(entt::registry& registry, entt::entity eid, const float3& position);
void set_transform(entt::registry& registry, entt::entity eid, const math::transform<float>& transform, bool warp = false); void set_transform(entt::registry& registry, entt::entity eid, const math::transform<float>& transform, bool warp = false);

+ 3
- 2
src/game/game-context.hpp View File

@ -54,7 +54,7 @@ class material_pass;
class nest_system; class nest_system;
class orbit_cam; class orbit_cam;
class pheromone_matrix; class pheromone_matrix;
class placement_system;
class snapping_system;
class point_light; class point_light;
class rasterizer; class rasterizer;
class render_system; class render_system;
@ -204,6 +204,7 @@ struct game_context
entt::entity flashlight_entity; entt::entity flashlight_entity;
entt::entity forceps_entity; entt::entity forceps_entity;
entt::entity lens_entity; entt::entity lens_entity;
entt::entity focal_point_entity;
// Systems // Systems
behavior_system* behavior_system; behavior_system* behavior_system;
@ -213,7 +214,7 @@ struct game_context
control_system* control_system; control_system* control_system;
locomotion_system* locomotion_system; locomotion_system* locomotion_system;
nest_system* nest_system; nest_system* nest_system;
placement_system* placement_system;
snapping_system* snapping_system;
render_system* render_system; render_system* render_system;
samara_system* samara_system; samara_system* samara_system;
subterrain_system* subterrain_system; subterrain_system* subterrain_system;

+ 31
- 10
src/game/states/play-state.cpp View File

@ -26,11 +26,12 @@
#include "game/components/copy-transform-component.hpp" #include "game/components/copy-transform-component.hpp"
#include "game/components/copy-translation-component.hpp" #include "game/components/copy-translation-component.hpp"
#include "game/components/model-component.hpp" #include "game/components/model-component.hpp"
#include "game/components/placement-component.hpp"
#include "game/components/snap-component.hpp"
#include "game/components/samara-component.hpp" #include "game/components/samara-component.hpp"
#include "game/components/terrain-component.hpp" #include "game/components/terrain-component.hpp"
#include "game/components/tool-component.hpp" #include "game/components/tool-component.hpp"
#include "game/components/transform-component.hpp" #include "game/components/transform-component.hpp"
#include "game/components/camera-subject-component.hpp"
#include "game/entity-commands.hpp" #include "game/entity-commands.hpp"
#include "game/game-context.hpp" #include "game/game-context.hpp"
#include "game/states/game-states.hpp" #include "game/states/game-states.hpp"
@ -42,6 +43,7 @@
#include "resources/resource-manager.hpp" #include "resources/resource-manager.hpp"
#include "scene/model-instance.hpp" #include "scene/model-instance.hpp"
#include "scene/scene.hpp" #include "scene/scene.hpp"
#include "scene/camera.hpp"
#include "game/systems/control-system.hpp" #include "game/systems/control-system.hpp"
#include "game/systems/camera-system.hpp" #include "game/systems/camera-system.hpp"
#include "utility/fundamental-types.hpp" #include "utility/fundamental-types.hpp"
@ -77,12 +79,15 @@ void play_state_enter(game_context* ctx)
ec::assign_render_layers(ecs_registry, flashlight_light_cone, 2); ec::assign_render_layers(ecs_registry, flashlight_light_cone, 2);
ecs::placement_component placement;
ecs::snap_component snap;
snap.warp = true;
snap.relative = false;
snap.autoremove = true;
auto ant_hill_entity = ant_hill_archetype->create(ecs_registry); auto ant_hill_entity = ant_hill_archetype->create(ecs_registry);
placement.ray.origin = {0, 10000, 0};
placement.ray.direction = {0, -1, 0};
ecs_registry.assign<ecs::placement_component>(ant_hill_entity, placement);
snap.ray.origin = {0, 10000, 0};
snap.ray.direction = {0, -1, 0};
ecs_registry.assign<ecs::snap_component>(ant_hill_entity, snap);
@ -101,14 +106,14 @@ void play_state_enter(game_context* ctx)
transform.transform.rotation = math::angle_axis(math::random(0.0f, math::two_pi<float>), {0, 1, 0}); transform.transform.rotation = math::angle_axis(math::random(0.0f, math::two_pi<float>), {0, 1, 0});
transform.transform.scale = float3{1, 1, 1} * math::random(0.75f, 1.25f); transform.transform.scale = float3{1, 1, 1} * math::random(0.75f, 1.25f);
placement.ray.origin = {x, 10000, z};
ecs_registry.assign<ecs::placement_component>(pebble_entity, placement);
snap.ray.origin = {x, 10000, z};
ecs_registry.assign<ecs::snap_component>(pebble_entity, snap);
} }
auto maple_tree_entity = maple_tree_archetype->create(ecs_registry); auto maple_tree_entity = maple_tree_archetype->create(ecs_registry);
placement.ray.origin = {300, 10000, 200};
placement.ray.direction = {0, -1, 0};
ecs_registry.assign<ecs::placement_component>(maple_tree_entity, placement);
snap.ray.origin = {300, 10000, 200};
snap.ray.direction = {0, -1, 0};
ecs_registry.assign<ecs::snap_component>(maple_tree_entity, snap);
auto nest_entity = nest_archetype->create(ecs_registry); auto nest_entity = nest_archetype->create(ecs_registry);
@ -151,8 +156,24 @@ void play_state_enter(game_context* ctx)
auto grass_entity_2 = grass_archetype->create(ecs_registry); auto grass_entity_2 = grass_archetype->create(ecs_registry);
ecs_registry.get<ecs::transform_component>(grass_entity_2).transform.rotation = math::angle_axis(math::radians(120.0f), float3{0, 1, 0}); ecs_registry.get<ecs::transform_component>(grass_entity_2).transform.rotation = math::angle_axis(math::radians(120.0f), float3{0, 1, 0});
*/ */
// Setup camera focal point
ecs::transform_component focal_point_transform;
focal_point_transform.transform = math::identity_transform<float>;
focal_point_transform.warp = true;
ecs::camera_subject_component focal_point_subject;
ecs::snap_component focal_point_snap;
focal_point_snap.ray = {float3{0, 10000, 0}, float3{0, -1, 0}};
focal_point_snap.warp = false;
focal_point_snap.relative = true;
focal_point_snap.autoremove = false;
ecs_registry.assign_or_replace<ecs::transform_component>(ctx->focal_point_entity, focal_point_transform);
ecs_registry.assign_or_replace<ecs::camera_subject_component>(ctx->focal_point_entity, focal_point_subject);
ecs_registry.assign_or_replace<ecs::snap_component>(ctx->focal_point_entity, focal_point_snap);
// Setup camera // Setup camera
ctx->overworld_camera->look_at({0, 0, 1}, {0, 0, 0}, {0, 1, 0});
ctx->camera_system->set_camera(ctx->overworld_camera); ctx->camera_system->set_camera(ctx->overworld_camera);
ctx->camera_system->set_azimuth(0.0f); ctx->camera_system->set_azimuth(0.0f);
ctx->camera_system->set_elevation(math::radians(45.0f)); ctx->camera_system->set_elevation(math::radians(45.0f));

+ 2
- 0
src/game/states/splash-state.cpp View File

@ -34,6 +34,8 @@ void splash_state_enter(game_context* ctx)
logger* logger = ctx->logger; logger* logger = ctx->logger;
logger->push_task("Entering splash state"); logger->push_task("Entering splash state");
//ctx->app->set_window_opacity(0.5f);
// Disable sky pass // Disable sky pass
ctx->overworld_sky_pass->set_enabled(false); ctx->overworld_sky_pass->set_enabled(false);

+ 69
- 41
src/game/systems/camera-system.cpp View File

@ -33,70 +33,81 @@ camera_system::camera_system(entt::registry& registry):
camera(nullptr), camera(nullptr),
viewport{0, 0, 0, 0}, viewport{0, 0, 0, 0},
mouse_position{0, 0} mouse_position{0, 0}
{}
{
// Init azimuth spring constraint
azimuth_spring.v = 0.0f;
azimuth_spring.z = 1.0f;
azimuth_spring.w = 2.0f * math::two_pi<float>;
// Init elevation spring constraint
elevation_spring.v = 0.0f;
elevation_spring.z = 1.0f;
elevation_spring.w = 2.0f * math::two_pi<float>;
// Init focal distance spring constraint
focal_distance_spring.v = 0.0f;
focal_distance_spring.z = 1.0f;
focal_distance_spring.w = 5.0f * math::two_pi<float>;
// Init fov spring constraint
fov_spring.v = 0.0f;
fov_spring.z = 1.0f;
fov_spring.w = 5.0f * math::two_pi<float>;
}
void camera_system::update(double t, double dt) void camera_system::update(double t, double dt)
{ {
if (!camera) if (!camera)
return; return;
// Determine focal point
// Determine target focal point
int subject_count = 0; int subject_count = 0;
float3 focal_point = {0, 0, 0};
float3 target_focal_point = {0, 0, 0};
registry.view<camera_subject_component, transform_component>().each( registry.view<camera_subject_component, transform_component>().each(
[&](auto entity, auto& subject, auto& transform) [&](auto entity, auto& subject, auto& transform)
{ {
focal_point += transform.transform.translation;
target_focal_point += transform.transform.translation;
++subject_count; ++subject_count;
}); });
if (subject_count > 1) if (subject_count > 1)
focal_point /= static_cast<float>(subject_count);
target_focal_point /= static_cast<float>(subject_count);
// Determine focal distance
float focal_distance = math::log_lerp<float>(focal_distance_far, focal_distance_near, zoom_factor);
// Determine view point
quaternion_type rotation = math::normalize(azimuth_rotation * elevation_rotation);
float3 view_point = focal_point + rotation * float3{0.0f, 0.0f, focal_distance};
// Update camera transform
// Get source transform
transform_type source_transform = camera->get_transform(); transform_type source_transform = camera->get_transform();
transform_type target_transform = math::identity_transform<float>;
target_transform.translation = view_point;
target_transform.rotation = rotation;
// Solve azimuth spring
float2 xz_direction = math::normalize(math::swizzle<0, 2>(target_focal_point) - math::swizzle<0, 2>(source_transform.translation));
azimuth_spring.x0 = math::wrap_radians(std::atan2(-xz_direction.y, xz_direction.x) - math::half_pi<float>);
azimuth_spring.x1 = azimuth_spring.x0 + math::wrap_radians(azimuth_spring.x1 - azimuth_spring.x0);
solve_spring_constraint<float, float>(azimuth_spring, dt);
float2 xz_direction = math::normalize(math::swizzle<0, 2>(focal_point) - math::swizzle<0, 2>(source_transform.translation));
float source_azimuth = math::wrap_radians(std::atan2(-xz_direction.y, xz_direction.x) - math::half_pi<float>);
float source_elevation = elevation;
// Sovle elevation spring
elevation_spring.x0 = elevation;
elevation_spring.x1 = elevation_spring.x0 + math::wrap_radians(elevation_spring.x1 - elevation_spring.x0);
solve_spring_constraint<float, float>(elevation_spring, dt);
float smooth_factor = 0.1f;
float smooth_azimuth = math::lerp_angle(source_azimuth, azimuth, smooth_factor);
float smooth_elevation = math::lerp_angle(source_elevation, elevation, smooth_factor);
// Solve focal distance spring
focal_distance_spring.x0 = math::length(source_transform.translation - target_focal_point);
solve_spring_constraint<float, float>(focal_distance_spring, dt);
// Solve FOV spring
fov_spring.x0 = camera->get_fov();
solve_spring_constraint<float, float>(fov_spring, dt);
smooth_azimuth = source_azimuth;
float shortest_angle = math::wrap_radians(azimuth - source_azimuth);
static float velocity = 0.0f;
spring<float, float>(smooth_azimuth, velocity, smooth_azimuth + shortest_angle, 1.0f, 2.0f * math::two_pi<float>, dt);
quaternion_type smooth_azimuth_rotation = math::angle_axis(smooth_azimuth, float3{0.0f, 1.0f, 0.0f});
quaternion_type smooth_elevation_rotation = math::angle_axis(smooth_elevation, float3{-1.0f, 0.0f, 0.0f});
// Determine camera rotation
quaternion_type smooth_azimuth_rotation = math::angle_axis(azimuth_spring.x0, float3{0.0f, 1.0f, 0.0f});
quaternion_type smooth_elevation_rotation = math::angle_axis(elevation_spring.x0, float3{-1.0f, 0.0f, 0.0f});
quaternion_type smooth_rotation = math::normalize(smooth_azimuth_rotation * smooth_elevation_rotation); quaternion_type smooth_rotation = math::normalize(smooth_azimuth_rotation * smooth_elevation_rotation);
float3 smooth_view_point = focal_point + smooth_rotation * float3{0.0f, 0.0f, focal_distance};
// Determine camera view point
float3 smooth_view_point = target_focal_point + smooth_rotation * float3{0.0f, 0.0f, focal_distance_spring.x0};
// Update camera transform
transform_type smooth_transform; transform_type smooth_transform;
smooth_transform.translation = smooth_view_point; smooth_transform.translation = smooth_view_point;
//smooth_transform.translation = math::lerp(source_transform.translation, target_transform.translation, smooth_factor);
//smooth_transform.rotation = math::slerp(source_transform.rotation, target_transform.rotation, smooth_factor);
smooth_transform.rotation = smooth_rotation; smooth_transform.rotation = smooth_rotation;
smooth_transform.scale = math::lerp(source_transform.scale, target_transform.scale, smooth_factor);
smooth_transform.scale = source_transform.scale;
camera->set_transform(smooth_transform); camera->set_transform(smooth_transform);
// Determine FOV
float fov = math::log_lerp<float>(fov_far, fov_near, zoom_factor);
// Determine aspect ratio // Determine aspect ratio
float aspect_ratio = viewport[2] / viewport[3]; float aspect_ratio = viewport[2] / viewport[3];
@ -106,7 +117,7 @@ void camera_system::update(double t, double dt)
float clip_far = math::log_lerp<float>(far_clip_far, far_clip_near, zoom_factor); float clip_far = math::log_lerp<float>(far_clip_far, far_clip_near, zoom_factor);
// Update camera projection // Update camera projection
camera->set_perspective(fov, aspect_ratio, clip_near, clip_far);
camera->set_perspective(fov_spring.x0, aspect_ratio, clip_near, clip_far);
} }
void camera_system::rotate(float angle) void camera_system::rotate(float angle)
@ -117,12 +128,11 @@ void camera_system::rotate(float angle)
void camera_system::tilt(float angle) void camera_system::tilt(float angle)
{ {
set_elevation(elevation + angle); set_elevation(elevation + angle);
} }
void camera_system::zoom(float factor) void camera_system::zoom(float factor)
{ {
set_zoom(std::max<float>(0.0f, std::min<float>(1.0f, zoom_factor + factor)));
set_zoom(zoom_factor + factor);
} }
void camera_system::set_camera(::camera* camera) void camera_system::set_camera(::camera* camera)
@ -139,29 +149,35 @@ void camera_system::set_azimuth(float angle)
{ {
azimuth = math::wrap_radians(angle); azimuth = math::wrap_radians(angle);
azimuth_rotation = math::angle_axis(azimuth, float3{0.0f, 1.0f, 0.0f}); azimuth_rotation = math::angle_axis(azimuth, float3{0.0f, 1.0f, 0.0f});
azimuth_spring.x1 = azimuth;
} }
void camera_system::set_elevation(float angle) void camera_system::set_elevation(float angle)
{ {
elevation = math::wrap_radians(angle); elevation = math::wrap_radians(angle);
elevation_rotation = math::angle_axis(elevation, float3{-1.0f, 0.0f, 0.0f}); elevation_rotation = math::angle_axis(elevation, float3{-1.0f, 0.0f, 0.0f});
elevation_spring.x1 = elevation;
} }
void camera_system::set_zoom(float factor) void camera_system::set_zoom(float factor)
{ {
this->zoom_factor = factor;
this->zoom_factor = std::max<float>(0.0f, std::min<float>(1.0f, factor));
update_focal_distance();
update_fov();
} }
void camera_system::set_focal_distance(float distance_near, float distance_far) void camera_system::set_focal_distance(float distance_near, float distance_far)
{ {
focal_distance_near = distance_near; focal_distance_near = distance_near;
focal_distance_far = distance_far; focal_distance_far = distance_far;
update_focal_distance();
} }
void camera_system::set_fov(float angle_near, float angle_far) void camera_system::set_fov(float angle_near, float angle_far)
{ {
fov_near = angle_near; fov_near = angle_near;
fov_far = angle_far; fov_far = angle_far;
update_fov();
} }
void camera_system::set_clip_near(float distance_near, float distance_far) void camera_system::set_clip_near(float distance_near, float distance_far)
@ -186,3 +202,15 @@ void camera_system::handle_event(const window_resized_event& event)
{ {
set_viewport({0.0f, 0.0f, static_cast<float>(event.w), static_cast<float>(event.h)}); set_viewport({0.0f, 0.0f, static_cast<float>(event.w), static_cast<float>(event.h)});
} }
void camera_system::update_focal_distance()
{
focal_distance = math::log_lerp<float>(focal_distance_far, focal_distance_near, zoom_factor);
focal_distance_spring.x1 = focal_distance;
}
void camera_system::update_fov()
{
fov = math::log_lerp<float>(fov_far, fov_near, zoom_factor);
fov_spring.x1 = fov;
}

+ 20
- 0
src/game/systems/camera-system.hpp View File

@ -27,6 +27,7 @@
#include "utility/fundamental-types.hpp" #include "utility/fundamental-types.hpp"
#include "math/quaternion-type.hpp" #include "math/quaternion-type.hpp"
#include "math/transform-type.hpp" #include "math/transform-type.hpp"
#include "animation/spring.hpp"
class camera; class camera;
class orbit_cam; class orbit_cam;
@ -56,18 +57,32 @@ public:
void set_fov(float angle_near, float angle_far); void set_fov(float angle_near, float angle_far);
void set_clip_near(float distance_near, float distance_far); void set_clip_near(float distance_near, float distance_far);
void set_clip_far(float distance_near, float distance_far); void set_clip_far(float distance_near, float distance_far);
const spring_constraint<float, float>& get_azimuth_spring() const;
private: private:
virtual void handle_event(const mouse_moved_event& event); virtual void handle_event(const mouse_moved_event& event);
virtual void handle_event(const window_resized_event& event); virtual void handle_event(const window_resized_event& event);
void update_focal_distance();
void update_fov();
camera* camera; camera* camera;
float4 viewport; float4 viewport;
float2 mouse_position; float2 mouse_position;
spring_constraint<float, float> azimuth_spring;
spring_constraint<float, float> elevation_spring;
spring_constraint<float, float> focal_distance_spring;
spring_constraint<float, float> fov_spring;
float azimuth; float azimuth;
float elevation; float elevation;
float focal_distance;
float zoom_factor; float zoom_factor;
float fov;
float focal_distance_near; float focal_distance_near;
float focal_distance_far; float focal_distance_far;
float fov_near; float fov_near;
@ -81,5 +96,10 @@ private:
quaternion_type azimuth_rotation; quaternion_type azimuth_rotation;
}; };
inline const spring_constraint<float, float>& camera_system::get_azimuth_spring() const
{
return azimuth_spring;
}
#endif // ANTKEEPER_CAMERA_SYSTEM_HPP #endif // ANTKEEPER_CAMERA_SYSTEM_HPP

+ 85
- 39
src/game/systems/control-system.cpp View File

@ -26,6 +26,7 @@
#include "nest.hpp" #include "nest.hpp"
#include "math/math.hpp" #include "math/math.hpp"
#include "game/entity-commands.hpp" #include "game/entity-commands.hpp"
#include "game/systems/camera-system.hpp"
control_system::control_system(entt::registry& registry): control_system::control_system(entt::registry& registry):
entity_system(registry), entity_system(registry),
@ -58,7 +59,7 @@ control_system::control_system(entt::registry& registry):
control->set_deadzone(0.15f); control->set_deadzone(0.15f);
} }
zoom_speed = 4.0f; //1
zoom_speed = 5.0f; //1
min_elevation = math::radians(-85.0f); min_elevation = math::radians(-85.0f);
max_elevation = math::radians(85.0f); max_elevation = math::radians(85.0f);
near_focal_distance = 2.0f; near_focal_distance = 2.0f;
@ -82,6 +83,74 @@ control_system::control_system(entt::registry& registry):
flashlight_turns_f = 0.0f; flashlight_turns_f = 0.0f;
} }
void control_system::update(double t, double dt)
{
// Zoom camera
if (zoom_in_control.is_active())
camera_system->zoom(zoom_speed * dt);
if (zoom_out_control.is_active())
camera_system->zoom(-zoom_speed * dt);
// Move camera
float3 movement{0.0f, 0.0f, 0.0f};
if (move_right_control.is_active())
movement.x += move_right_control.get_current_value();
if (move_left_control.is_active())
movement.x -= move_left_control.get_current_value();
if (move_forward_control.is_active())
movement.z -= move_forward_control.get_current_value();
if (move_back_control.is_active())
movement.z += move_back_control.get_current_value();
if (math::length_squared(movement) != 0.0f)
{
float max_speed = 100.0f * dt;
float speed = std::min<float>(max_speed, math::length(movement * max_speed));
movement = math::normalize(movement) * speed;
float azimuth = camera_system->get_azimuth_spring().x0;
math::quaternion<float> azimuth_rotation = math::angle_axis(azimuth, float3{0.0f, 1.0f, 0.0f});
movement = azimuth_rotation * movement;
ec::translate(registry, camera_subject_eid, movement);
}
// Turn flashlight
float2 viewport_center = {(viewport[0] + viewport[2]) * 0.5f, (viewport[1] + viewport[3]) * 0.5f};
float2 mouse_direction = math::normalize(mouse_position - viewport_center);
old_mouse_angle = mouse_angle;
mouse_angle = std::atan2(-mouse_direction.y, mouse_direction.x);
if (mouse_angle - old_mouse_angle != 0.0f)
{
if (mouse_angle - old_mouse_angle <= -math::pi<float>)
flashlight_turns_i -= 1;
else if (mouse_angle - old_mouse_angle >= math::pi<float>)
flashlight_turns_i += 1;
flashlight_turns_f = (mouse_angle) / math::two_pi<float>;
flashlight_turns = flashlight_turns_i - flashlight_turns_f;
if (flashlight_eid != entt::null && nest)
{
math::transform<float> flashlight_transform = math::identity_transform<float>;
float flashlight_depth = nest->get_shaft_depth(*nest->get_central_shaft(), flashlight_turns);
flashlight_transform.translation = {0.0f, -flashlight_depth, 0.0f};
flashlight_transform.rotation = math::angle_axis(-flashlight_turns * math::two_pi<float> + math::half_pi<float>, {0, 1, 0});
ec::set_transform(registry, flashlight_eid, flashlight_transform, false);
if (underworld_camera)
{
underworld_camera->look_at({0, -flashlight_depth + 50.0f, 0}, {0, -flashlight_depth, 0}, {0, 0, -1});
}
}
}
}
/*
void control_system::update(double t, double dt) void control_system::update(double t, double dt)
{ {
this->timestep = dt; this->timestep = dt;
@ -205,52 +274,20 @@ void control_system::update(double t, double dt)
} }
// Turn flashlight
float2 viewport_center = {(viewport[0] + viewport[2]) * 0.5f, (viewport[1] + viewport[3]) * 0.5f};
float2 mouse_direction = math::normalize(mouse_position - viewport_center);
old_mouse_angle = mouse_angle;
mouse_angle = std::atan2(-mouse_direction.y, mouse_direction.x);
if (mouse_angle - old_mouse_angle != 0.0f)
{
if (mouse_angle - old_mouse_angle <= -math::pi<float>)
flashlight_turns_i -= 1;
else if (mouse_angle - old_mouse_angle >= math::pi<float>)
flashlight_turns_i += 1;
flashlight_turns_f = (mouse_angle) / math::two_pi<float>;
flashlight_turns = flashlight_turns_i - flashlight_turns_f;
if (flashlight_eid != entt::null && nest)
{
math::transform<float> flashlight_transform = math::identity_transform<float>;
float flashlight_depth = nest->get_shaft_depth(*nest->get_central_shaft(), flashlight_turns);
flashlight_transform.translation = {0.0f, -flashlight_depth, 0.0f};
flashlight_transform.rotation = math::angle_axis(-flashlight_turns * math::two_pi<float> + math::half_pi<float>, {0, 1, 0});
ec::set_transform(registry, flashlight_eid, flashlight_transform, false);
if (underworld_camera)
{
underworld_camera->look_at({0, -flashlight_depth + 50.0f, 0}, {0, -flashlight_depth, 0}, {0, 0, -1});
}
}
}
} }
*/
void control_system::set_orbit_cam(::orbit_cam* orbit_cam) void control_system::set_orbit_cam(::orbit_cam* orbit_cam)
{ {
this->orbit_cam = orbit_cam; this->orbit_cam = orbit_cam;
} }
void control_system::set_camera_system(::camera_system* camera_system)
{
this->camera_system = camera_system;
}
void control_system::set_nest(::nest* nest) void control_system::set_nest(::nest* nest)
{ {
this->nest = nest; this->nest = nest;
@ -266,6 +303,11 @@ void control_system::set_flashlight(entt::entity eid)
flashlight_eid = eid; flashlight_eid = eid;
} }
void control_system::set_camera_subject(entt::entity eid)
{
camera_subject_eid = eid;
}
void control_system::set_viewport(const float4& viewport) void control_system::set_viewport(const float4& viewport)
{ {
this->viewport = viewport; this->viewport = viewport;
@ -309,3 +351,7 @@ void control_system::handle_event(const mouse_moved_event& event)
} }
} }
void control_system::handle_event(const window_resized_event& event)
{
set_viewport({0.0f, 0.0f, static_cast<float>(event.w), static_cast<float>(event.h)});
}

+ 9
- 1
src/game/systems/control-system.hpp View File

@ -23,6 +23,7 @@
#include "game/systems/entity-system.hpp" #include "game/systems/entity-system.hpp"
#include "event/event-handler.hpp" #include "event/event-handler.hpp"
#include "event/input-events.hpp" #include "event/input-events.hpp"
#include "event/window-events.hpp"
#include "input/control.hpp" #include "input/control.hpp"
#include "input/control-set.hpp" #include "input/control-set.hpp"
#include "scene/model-instance.hpp" #include "scene/model-instance.hpp"
@ -31,10 +32,12 @@
class orbit_cam; class orbit_cam;
class nest; class nest;
class camera; class camera;
class camera_system;
class control_system: class control_system:
public entity_system, public entity_system,
public event_handler<mouse_moved_event>
public event_handler<mouse_moved_event>,
public event_handler<window_resized_event>
{ {
public: public:
control_system(entt::registry& registry); control_system(entt::registry& registry);
@ -45,9 +48,11 @@ public:
void set_invert_mouse_y(bool invert); void set_invert_mouse_y(bool invert);
void set_orbit_cam(orbit_cam* orbit_cam); void set_orbit_cam(orbit_cam* orbit_cam);
void set_camera_system(camera_system* camera_system);
void set_nest(::nest* nest); void set_nest(::nest* nest);
void set_tool(model_instance* tool); void set_tool(model_instance* tool);
void set_flashlight(entt::entity eid); void set_flashlight(entt::entity eid);
void set_camera_subject(entt::entity eid);
void set_viewport(const float4& viewport); void set_viewport(const float4& viewport);
void set_underworld_camera(::camera* camera); void set_underworld_camera(::camera* camera);
@ -71,6 +76,7 @@ public:
private: private:
virtual void handle_event(const mouse_moved_event& event); virtual void handle_event(const mouse_moved_event& event);
virtual void handle_event(const window_resized_event& event);
control_set control_set; control_set control_set;
control move_forward_control; control move_forward_control;
@ -106,12 +112,14 @@ private:
float timestep; float timestep;
float zoom; float zoom;
orbit_cam* orbit_cam; orbit_cam* orbit_cam;
camera_system* camera_system;
::nest* nest; ::nest* nest;
model_instance* tool; model_instance* tool;
float2 mouse_position; float2 mouse_position;
float4 viewport; float4 viewport;
entt::entity flashlight_eid; entt::entity flashlight_eid;
entt::entity camera_subject_eid;
camera* underworld_camera; camera* underworld_camera;
float mouse_angle; float mouse_angle;

src/game/systems/placement-system.cpp → src/game/systems/snapping-system.cpp View File

@ -17,35 +17,41 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "placement-system.hpp"
#include "snapping-system.hpp"
#include "game/components/collision-component.hpp" #include "game/components/collision-component.hpp"
#include "game/components/placement-component.hpp"
#include "game/components/snap-component.hpp"
#include "game/components/transform-component.hpp" #include "game/components/transform-component.hpp"
#include "game/components/terrain-component.hpp"
#include "utility/fundamental-types.hpp" #include "utility/fundamental-types.hpp"
using namespace ecs; using namespace ecs;
placement_system::placement_system(entt::registry& registry):
snapping_system::snapping_system(entt::registry& registry):
entity_system(registry) entity_system(registry)
{} {}
void placement_system::update(double t, double dt)
void snapping_system::update(double t, double dt)
{ {
registry.view<transform_component, placement_component>().each(
[&](auto entity, auto& transform, auto& placement)
registry.view<transform_component, snap_component>().each(
[&](auto entity, auto& snap_transform, auto& snap)
{ {
bool intersection = false; bool intersection = false;
float a = std::numeric_limits<float>::infinity(); float a = std::numeric_limits<float>::infinity();
float3 pick; float3 pick;
ray<float> snap_ray = snap.ray;
if (snap.relative)
{
snap_ray.origin += snap_transform.transform.translation;
snap_ray.direction = snap_transform.transform.rotation * snap_ray.direction;
}
registry.view<transform_component, collision_component>().each( registry.view<transform_component, collision_component>().each(
[&](auto entity, auto& transform, auto& collision)
[&](auto entity, auto& collision_transform, auto& collision)
{ {
// Transform ray into local space of collision component // Transform ray into local space of collision component
math::transform<float> inverse_transform = math::inverse(transform.transform);
float3 origin = inverse_transform * placement.ray.origin;
float3 direction = math::normalize(math::conjugate(transform.transform.rotation) * placement.ray.direction);
math::transform<float> inverse_transform = math::inverse(collision_transform.transform);
float3 origin = inverse_transform * snap_ray.origin;
float3 direction = math::normalize(math::conjugate(collision_transform.transform.rotation) * snap_ray.direction);
ray<float> transformed_ray = {origin, direction}; ray<float> transformed_ray = {origin, direction};
// Broad phase AABB test // Broad phase AABB test
@ -55,6 +61,7 @@ void placement_system::update(double t, double dt)
return; return;
} }
// Narrow phase mesh test
auto mesh_result = collision.mesh_accelerator.query_nearest(transformed_ray); auto mesh_result = collision.mesh_accelerator.query_nearest(transformed_ray);
if (mesh_result) if (mesh_result)
{ {
@ -62,17 +69,20 @@ void placement_system::update(double t, double dt)
if (mesh_result->t < a) if (mesh_result->t < a)
{ {
a = mesh_result->t; a = mesh_result->t;
pick = placement.ray.extrapolate(a);
pick = snap_ray.extrapolate(a);
} }
} }
}); });
if (intersection) if (intersection)
{ {
transform.transform.translation = pick;
transform.warp = true;
registry.remove<placement_component>(entity);
snap_transform.transform.translation = pick;
snap_transform.warp = snap.warp;
if (snap.autoremove)
{
registry.remove<snap_component>(entity);
}
} }
}); });
} }

src/game/systems/placement-system.hpp → src/game/systems/snapping-system.hpp View File

@ -17,18 +17,18 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ANTKEEPER_PLACEMENT_SYSTEM_HPP
#define ANTKEEPER_PLACEMENT_SYSTEM_HPP
#ifndef ANTKEEPER_SNAPPING_SYSTEM_HPP
#define ANTKEEPER_SNAPPING_SYSTEM_HPP
#include "entity-system.hpp" #include "entity-system.hpp"
class placement_system:
class snapping_system:
public entity_system public entity_system
{ {
public: public:
placement_system(entt::registry& registry);
snapping_system(entt::registry& registry);
virtual void update(double t, double dt); virtual void update(double t, double dt);
}; };
#endif // ANTKEEPER_PLACEMENT_SYSTEM_HPP
#endif // ANTKEEPER_SNAPPING_SYSTEM_HPP

+ 1
- 1
src/game/systems/vegetation-system.cpp View File

@ -169,7 +169,7 @@ void vegetation_system::on_terrain_construct(entt::registry& registry, entt::ent
lod_group->update_tweens(); lod_group->update_tweens();
// Add LOD group to scene // Add LOD group to scene
//scene->add_object(lod_group);
scene->add_object(lod_group);
} }
} }
} }

Loading…
Cancel
Save