💿🐜 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.

113 lines
4.7 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "game/systems/camera-system.hpp"
  20. #include "game/components/orbit-camera-component.hpp"
  21. #include "game/components/scene-component.hpp"
  22. #include <engine/animation/ease.hpp>
  23. #include <engine/math/projection.hpp>
  24. #include <engine/scene/camera.hpp>
  25. #include <execution>
  26. camera_system::camera_system(entity::registry& registry):
  27. updatable_system(registry)
  28. {}
  29. void camera_system::update(float t, float dt)
  30. {
  31. }
  32. void camera_system::interpolate(float alpha)
  33. {
  34. auto orbit_cam_group = registry.group<orbit_camera_component>(entt::get<scene_component>);
  35. std::for_each
  36. (
  37. std::execution::seq,
  38. orbit_cam_group.begin(),
  39. orbit_cam_group.end(),
  40. [&](auto entity_id)
  41. {
  42. auto& orbit_cam = orbit_cam_group.get<orbit_camera_component>(entity_id);
  43. auto& scene = orbit_cam_group.get<scene_component>(entity_id);
  44. auto& camera = static_cast<scene::camera&>(*scene.object);
  45. math::transform<double> subject_transform = math::transform<double>::identity();
  46. if (orbit_cam.subject_eid != entt::null)
  47. {
  48. const auto subject_scene = registry.try_get<scene_component>(orbit_cam.subject_eid);
  49. if (subject_scene)
  50. {
  51. subject_transform.translation = math::dvec3(subject_scene->object->get_translation());
  52. subject_transform.rotation = math::dquat(subject_scene->object->get_rotation());
  53. }
  54. }
  55. // Calculate focal point
  56. const auto focal_point = subject_transform * orbit_cam.focal_point;
  57. // Clamp zoom
  58. orbit_cam.zoom = std::min<double>(std::max<double>(orbit_cam.zoom, 0.0), 1.0);
  59. // Update FoV
  60. orbit_cam.hfov = ease<double, double>::out_sine(orbit_cam.far_hfov, orbit_cam.near_hfov, orbit_cam.zoom);
  61. orbit_cam.vfov = math::vertical_fov(orbit_cam.hfov, static_cast<double>(camera.get_aspect_ratio()));
  62. // Update focal plane size
  63. orbit_cam.focal_plane_height = ease<double, double>::out_sine(orbit_cam.far_focal_plane_height, orbit_cam.near_focal_plane_height, orbit_cam.zoom);
  64. orbit_cam.focal_plane_width = orbit_cam.focal_plane_height * static_cast<double>(camera.get_aspect_ratio());
  65. // Update focal distance
  66. orbit_cam.focal_distance = orbit_cam.focal_plane_height * 0.5 / std::tan(orbit_cam.vfov * 0.5);
  67. const auto camera_up = orbit_cam.up_rotation * math::dvec3{0, 1, 0};
  68. const auto subject_up = subject_transform.rotation * math::dvec3{0, 1, 0};
  69. orbit_cam.up_rotation = math::normalize(math::rotation(camera_up, subject_up) * orbit_cam.up_rotation);
  70. // Update orientation
  71. orbit_cam.yaw_rotation = math::angle_axis(orbit_cam.yaw, {0.0, 1.0, 0.0});
  72. orbit_cam.pitch_rotation = math::angle_axis(orbit_cam.pitch, {-1.0, 0.0, 0.0});
  73. orbit_cam.orientation = math::normalize(orbit_cam.up_rotation * math::normalize(orbit_cam.yaw_rotation * orbit_cam.pitch_rotation));
  74. // orbit_cam.orientation = math::normalize(subject_transform.rotation * math::normalize(orbit_cam.yaw_rotation * orbit_cam.pitch_rotation));
  75. // orbit_cam.orientation = math::normalize(math::normalize(orbit_cam.yaw_rotation * orbit_cam.pitch_rotation));
  76. // Update transform
  77. const auto camera_translation = focal_point + orbit_cam.orientation * math::dvec3{0.0f, 0.0f, orbit_cam.focal_distance};
  78. math::transform<float> camera_transform;
  79. camera_transform.translation = math::fvec3(camera_translation);
  80. camera_transform.rotation = math::fquat(orbit_cam.orientation);
  81. camera_transform.scale = {1, 1, 1};
  82. // double center_offset = (1.0 - std::abs(orbit_cam.pitch) / math::half_pi<double>) * (orbit_cam.focal_plane_height / 3.0 * 0.5);
  83. // camera_transform.translation += math::fvec3(orbit_cam.orientation * math::dvec3{0, center_offset, 0});
  84. camera.set_transform(camera_transform);
  85. camera.set_perspective(static_cast<float>(orbit_cam.vfov), camera.get_aspect_ratio(), camera.get_clip_near(), camera.get_clip_far());
  86. }
  87. );
  88. }
  89. void camera_system::set_viewport(const math::fvec4& viewport)
  90. {
  91. m_viewport = math::dvec4(viewport);
  92. m_aspect_ratio = m_viewport[2] / m_viewport[3];
  93. }