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

311 lines
9.4 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 "control-system.hpp"
  20. #include "input/control.hpp"
  21. #include "orbit-cam.hpp"
  22. #include "scene/camera.hpp"
  23. #include "geometry/intersection.hpp"
  24. #include "animation/ease.hpp"
  25. #include "nest.hpp"
  26. #include "math/math.hpp"
  27. #include "game/entity-commands.hpp"
  28. control_system::control_system(entt::registry& registry):
  29. entity_system(registry),
  30. timestep(0.0f),
  31. zoom(0.0f),
  32. tool(nullptr),
  33. flashlight_eid(entt::null),
  34. underworld_camera(nullptr)
  35. {
  36. control_set.add_control(&move_forward_control);
  37. control_set.add_control(&move_back_control);
  38. control_set.add_control(&move_right_control);
  39. control_set.add_control(&move_left_control);
  40. control_set.add_control(&rotate_ccw_control);
  41. control_set.add_control(&rotate_cw_control);
  42. control_set.add_control(&tilt_up_control);
  43. control_set.add_control(&tilt_down_control);
  44. control_set.add_control(&zoom_in_control);
  45. control_set.add_control(&zoom_out_control);
  46. control_set.add_control(&adjust_camera_control);
  47. control_set.add_control(&ascend_control);
  48. control_set.add_control(&descend_control);
  49. control_set.add_control(&toggle_view_control);
  50. control_set.add_control(&tool_menu_control);
  51. // Set deadzone at 15% for all controls
  52. const std::list<control*>* controls = control_set.get_controls();
  53. for (control* control: *controls)
  54. {
  55. control->set_deadzone(0.15f);
  56. }
  57. zoom_speed = 4.0f; //1
  58. min_elevation = math::radians(-85.0f);
  59. max_elevation = math::radians(85.0f);
  60. near_focal_distance = 2.0f;
  61. far_focal_distance = 200.0f;
  62. near_movement_speed = 10.0f;
  63. far_movement_speed = 80.0f;
  64. near_fov = math::radians(80.0f);
  65. far_fov = math::radians(35.0f);
  66. near_clip_near = 0.1f;
  67. far_clip_near = 5.0f;
  68. near_clip_far = 100.0f;
  69. far_clip_far = 2000.0f;
  70. nest = nullptr;
  71. orbit_cam = nullptr;
  72. mouse_angle = 0.0f;
  73. old_mouse_angle = mouse_angle;
  74. flashlight_turns = 0.0f;
  75. flashlight_turns_i = 0;
  76. flashlight_turns_f = 0.0f;
  77. }
  78. void control_system::update(double t, double dt)
  79. {
  80. this->timestep = dt;
  81. if (adjust_camera_control.is_active() && !adjust_camera_control.was_active())
  82. {
  83. }
  84. // Determine zoom
  85. if (zoom_in_control.is_active())
  86. zoom += zoom_speed * dt * zoom_in_control.get_current_value();
  87. if (zoom_out_control.is_active())
  88. zoom -= zoom_speed * dt * zoom_out_control.get_current_value();
  89. zoom = std::max<float>(0.0f, std::min<float>(1.0f, zoom));
  90. float focal_distance = math::log_lerp<float>(near_focal_distance, far_focal_distance, 1.0f - zoom);
  91. float fov = math::log_lerp<float>(near_fov, far_fov, 1.0f - zoom);
  92. //float elevation_factor = (orbit_cam->get_target_elevation() - min_elevation) / max_elevation;
  93. //fov = math::log_lerp<float>(near_fov, far_fov, elevation_factor);
  94. float clip_near = math::log_lerp<float>(near_clip_near, far_clip_near, 1.0f - zoom);
  95. float clip_far = math::log_lerp<float>(near_clip_far, far_clip_far, 1.0f - zoom);
  96. float movement_speed = math::log_lerp<float>(near_movement_speed * dt, far_movement_speed * dt, 1.0f - zoom);
  97. orbit_cam->set_target_focal_distance(focal_distance);
  98. orbit_cam->get_camera()->set_perspective(fov, orbit_cam->get_camera()->get_aspect_ratio(), clip_near, clip_far);
  99. const float rotation_speed = 2.0f * dt;
  100. float rotation = 0.0f;
  101. if (rotate_ccw_control.is_active())
  102. rotation += rotate_ccw_control.get_current_value() * rotation_speed;
  103. if (rotate_cw_control.is_active())
  104. rotation -= rotate_cw_control.get_current_value() * rotation_speed;
  105. if (rotation)
  106. {
  107. orbit_cam->rotate(rotation);
  108. }
  109. const float tilt_speed = 2.0f * dt;
  110. float tilt = 0.0f;
  111. if (tilt_up_control.is_active())
  112. tilt -= tilt_up_control.get_current_value() * tilt_speed;
  113. if (tilt_down_control.is_active())
  114. tilt += tilt_down_control.get_current_value() * tilt_speed;
  115. if (tilt)
  116. {
  117. orbit_cam->tilt(tilt);
  118. float elevation = orbit_cam->get_target_elevation();
  119. elevation = std::min<float>(max_elevation, std::max<float>(min_elevation, elevation));
  120. orbit_cam->set_target_elevation(elevation);
  121. }
  122. float2 movement{0.0f, 0.0f};
  123. if (move_right_control.is_active())
  124. movement[0] += move_right_control.get_current_value();
  125. if (move_left_control.is_active())
  126. movement[0] -= move_left_control.get_current_value();
  127. if (move_forward_control.is_active())
  128. movement[1] -= move_forward_control.get_current_value();
  129. if (move_back_control.is_active())
  130. movement[1] += move_back_control.get_current_value();
  131. const float deadzone = 0.01f;
  132. float magnitude_squared = math::length_squared(movement);
  133. if (magnitude_squared > deadzone)
  134. {
  135. if (magnitude_squared > 1.0f)
  136. {
  137. movement = math::normalize(movement);
  138. }
  139. orbit_cam->move(movement * movement_speed);
  140. }
  141. float ascention = 0.0f;
  142. if (ascend_control.is_active())
  143. ascention += ascend_control.get_current_value();
  144. if (descend_control.is_active())
  145. ascention -= descend_control.get_current_value();
  146. if (ascention)
  147. {
  148. float old_depth = -orbit_cam->get_target_focal_point()[1];
  149. orbit_cam->set_target_focal_point(orbit_cam->get_target_focal_point() + float3{0.0f, ascention * movement_speed, 0.0f});
  150. if (nest)
  151. {
  152. float3 focal_point = orbit_cam->get_target_focal_point();
  153. float depth = -focal_point[1];
  154. float delta_shaft_angle = nest->get_shaft_angle(*nest->get_central_shaft(), depth) - nest->get_shaft_angle(*nest->get_central_shaft(), old_depth);
  155. //orbit_cam->set_target_azimuth(orbit_cam->get_target_azimuth() - delta_shaft_angle);
  156. orbit_cam->set_target_focal_point(nest->get_shaft_position(*nest->get_central_shaft(), depth));
  157. }
  158. }
  159. orbit_cam->update(dt);
  160. camera* camera = orbit_cam->get_camera();
  161. float3 pick_near = camera->unproject({mouse_position[0], viewport[3] - mouse_position[1], 0.0f}, viewport);
  162. float3 pick_far = camera->unproject({mouse_position[0], viewport[3] - mouse_position[1], 1.0f}, viewport);
  163. float3 pick_direction = math::normalize(pick_far - pick_near);
  164. ray<float> picking_ray = {pick_near, pick_direction};
  165. plane<float> ground_plane = {float3{0, 1, 0}, 0.0f};
  166. auto intersection_result = ray_plane_intersection(picking_ray, ground_plane);
  167. if (std::get<0>(intersection_result))
  168. {
  169. float3 pick = picking_ray.extrapolate(std::get<1>(intersection_result));
  170. if (tool)
  171. tool->set_translation(pick);
  172. }
  173. if (toggle_view_control.is_active() && !toggle_view_control.was_active())
  174. {
  175. }
  176. // Turn flashlight
  177. float2 viewport_center = {(viewport[0] + viewport[2]) * 0.5f, (viewport[1] + viewport[3]) * 0.5f};
  178. float2 mouse_direction = math::normalize(mouse_position - viewport_center);
  179. old_mouse_angle = mouse_angle;
  180. mouse_angle = std::atan2(-mouse_direction.y, mouse_direction.x);
  181. if (mouse_angle - old_mouse_angle != 0.0f)
  182. {
  183. if (mouse_angle - old_mouse_angle <= -math::pi<float>)
  184. flashlight_turns_i -= 1;
  185. else if (mouse_angle - old_mouse_angle >= math::pi<float>)
  186. flashlight_turns_i += 1;
  187. flashlight_turns_f = (mouse_angle) / math::two_pi<float>;
  188. flashlight_turns = flashlight_turns_i - flashlight_turns_f;
  189. if (flashlight_eid != entt::null && nest)
  190. {
  191. math::transform<float> flashlight_transform = math::identity_transform<float>;
  192. float flashlight_depth = nest->get_shaft_depth(*nest->get_central_shaft(), flashlight_turns);
  193. flashlight_transform.translation = {0.0f, -flashlight_depth, 0.0f};
  194. flashlight_transform.rotation = math::angle_axis(-flashlight_turns * math::two_pi<float> + math::half_pi<float>, {0, 1, 0});
  195. ec::set_transform(registry, flashlight_eid, flashlight_transform, false);
  196. if (underworld_camera)
  197. {
  198. underworld_camera->look_at({0, -flashlight_depth + 50.0f, 0}, {0, -flashlight_depth, 0}, {0, 0, -1});
  199. }
  200. }
  201. }
  202. }
  203. void control_system::set_orbit_cam(::orbit_cam* orbit_cam)
  204. {
  205. this->orbit_cam = orbit_cam;
  206. }
  207. void control_system::set_nest(::nest* nest)
  208. {
  209. this->nest = nest;
  210. }
  211. void control_system::set_tool(model_instance* tool)
  212. {
  213. this->tool = tool;
  214. }
  215. void control_system::set_flashlight(entt::entity eid)
  216. {
  217. flashlight_eid = eid;
  218. }
  219. void control_system::set_viewport(const float4& viewport)
  220. {
  221. this->viewport = viewport;
  222. }
  223. void control_system::set_underworld_camera(::camera* camera)
  224. {
  225. this->underworld_camera = camera;
  226. }
  227. void control_system::handle_event(const mouse_moved_event& event)
  228. {
  229. if (adjust_camera_control.is_active())
  230. {
  231. bool invert_x = true;
  232. bool invert_y = false;
  233. float rotation_factor = event.dx;
  234. float elevation_factor = event.dy;
  235. if (invert_x)
  236. {
  237. rotation_factor *= -1.0f;
  238. }
  239. if (invert_y)
  240. {
  241. elevation_factor *= -1.0f;
  242. }
  243. float rotation = math::radians(22.5f) * rotation_factor * timestep;
  244. float elevation = orbit_cam->get_target_elevation() + elevation_factor * 0.25f * timestep;
  245. elevation = std::min<float>(max_elevation, std::max<float>(min_elevation, elevation));
  246. orbit_cam->rotate(rotation);
  247. orbit_cam->set_target_elevation(elevation);
  248. }
  249. else if (!adjust_camera_control.was_active())
  250. {
  251. mouse_position[0] = event.x;
  252. mouse_position[1] = event.y;
  253. }
  254. }