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

183 lines
5.8 KiB

  1. /*
  2. * Copyright (C) 2020 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 "camera-system.hpp"
  20. #include "game/components/camera-subject-component.hpp"
  21. #include "game/components/transform-component.hpp"
  22. #include "scene/camera.hpp"
  23. #include "math/math.hpp"
  24. #include <cmath>
  25. #include <iostream>
  26. using namespace ecs;
  27. camera_system::camera_system(entt::registry& registry):
  28. entity_system(registry),
  29. camera(nullptr),
  30. viewport{0, 0, 0, 0},
  31. mouse_position{0, 0}
  32. {}
  33. void camera_system::update(double t, double dt)
  34. {
  35. if (!camera)
  36. return;
  37. // Determine focal point
  38. int subject_count = 0;
  39. float3 focal_point = {0, 0, 0};
  40. registry.view<camera_subject_component, transform_component>().each(
  41. [&](auto entity, auto& subject, auto& transform)
  42. {
  43. focal_point += transform.transform.translation;
  44. ++subject_count;
  45. });
  46. if (subject_count > 1)
  47. focal_point /= static_cast<float>(subject_count);
  48. // Determine focal distance
  49. float focal_distance = math::log_lerp<float>(focal_distance_far, focal_distance_near, zoom_factor);
  50. // Determine view point
  51. quaternion_type rotation = math::normalize(azimuth_rotation * elevation_rotation);
  52. float3 view_point = focal_point + rotation * float3{0.0f, 0.0f, focal_distance};
  53. // Update camera transform
  54. transform_type source_transform = camera->get_transform();
  55. transform_type target_transform = math::identity_transform<float>;
  56. target_transform.translation = view_point;
  57. target_transform.rotation = rotation;
  58. float2 xz_direction = math::normalize(math::swizzle<0, 2>(focal_point) - math::swizzle<0, 2>(source_transform.translation));
  59. float source_azimuth = math::wrap_radians(std::atan2(-xz_direction.y, xz_direction.x) - math::half_pi<float>);
  60. float source_elevation = elevation;
  61. std::cout << "azimuth: " << math::degrees(azimuth) << "\n";
  62. std::cout << "source azimuth: " << math::degrees(source_azimuth) << "\n";
  63. float smooth_factor = 0.1f;
  64. float smooth_azimuth = math::lerp_angle(source_azimuth, azimuth, smooth_factor);
  65. float smooth_elevation = math::lerp_angle(source_elevation, elevation, smooth_factor);
  66. quaternion_type smooth_azimuth_rotation = math::angle_axis(smooth_azimuth, float3{0.0f, 1.0f, 0.0f});
  67. quaternion_type smooth_elevation_rotation = math::angle_axis(smooth_elevation, float3{-1.0f, 0.0f, 0.0f});
  68. quaternion_type smooth_rotation = math::normalize(smooth_azimuth_rotation * smooth_elevation_rotation);
  69. float3 smooth_view_point = focal_point + smooth_rotation * float3{0.0f, 0.0f, focal_distance};
  70. transform_type smooth_transform;
  71. smooth_transform.translation = smooth_view_point;
  72. //smooth_transform.translation = math::lerp(source_transform.translation, target_transform.translation, smooth_factor);
  73. //smooth_transform.rotation = math::slerp(source_transform.rotation, target_transform.rotation, smooth_factor);
  74. smooth_transform.rotation = smooth_rotation;
  75. smooth_transform.scale = math::lerp(source_transform.scale, target_transform.scale, smooth_factor);
  76. camera->set_transform(smooth_transform);
  77. // Determine FOV
  78. float fov = math::log_lerp<float>(fov_far, fov_near, zoom_factor);
  79. // Determine aspect ratio
  80. float aspect_ratio = viewport[2] / viewport[3];
  81. // Determine clipping planes
  82. float clip_near = math::log_lerp<float>(near_clip_far, near_clip_near, zoom_factor);
  83. float clip_far = math::log_lerp<float>(far_clip_far, far_clip_near, zoom_factor);
  84. // Update camera projection
  85. camera->set_perspective(fov, aspect_ratio, clip_near, clip_far);
  86. }
  87. void camera_system::rotate(float angle)
  88. {
  89. set_azimuth(azimuth + angle);
  90. }
  91. void camera_system::tilt(float angle)
  92. {
  93. set_elevation(elevation + angle);
  94. }
  95. void camera_system::zoom(float factor)
  96. {
  97. set_zoom(std::max<float>(0.0f, std::min<float>(1.0f, zoom_factor + factor)));
  98. }
  99. void camera_system::set_camera(::camera* camera)
  100. {
  101. this->camera = camera;
  102. }
  103. void camera_system::set_viewport(const float4& viewport)
  104. {
  105. this->viewport = viewport;
  106. }
  107. void camera_system::set_azimuth(float angle)
  108. {
  109. azimuth = math::wrap_radians(angle);
  110. azimuth_rotation = math::angle_axis(azimuth, float3{0.0f, 1.0f, 0.0f});
  111. }
  112. void camera_system::set_elevation(float angle)
  113. {
  114. elevation = math::wrap_radians(angle);
  115. elevation_rotation = math::angle_axis(elevation, float3{-1.0f, 0.0f, 0.0f});
  116. }
  117. void camera_system::set_zoom(float factor)
  118. {
  119. this->zoom_factor = factor;
  120. }
  121. void camera_system::set_focal_distance(float distance_near, float distance_far)
  122. {
  123. focal_distance_near = distance_near;
  124. focal_distance_far = distance_far;
  125. }
  126. void camera_system::set_fov(float angle_near, float angle_far)
  127. {
  128. fov_near = angle_near;
  129. fov_far = angle_far;
  130. }
  131. void camera_system::set_clip_near(float distance_near, float distance_far)
  132. {
  133. near_clip_near = distance_near;
  134. near_clip_far = distance_far;
  135. }
  136. void camera_system::set_clip_far(float distance_near, float distance_far)
  137. {
  138. far_clip_near = distance_near;
  139. far_clip_far = distance_far;
  140. }
  141. void camera_system::handle_event(const mouse_moved_event& event)
  142. {
  143. mouse_position[0] = event.x;
  144. mouse_position[1] = event.y;
  145. }
  146. void camera_system::handle_event(const window_resized_event& event)
  147. {
  148. set_viewport({0.0f, 0.0f, static_cast<float>(event.w), static_cast<float>(event.h)});
  149. }