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

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