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

868 lines
27 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/state/nuptial-flight.hpp"
  20. #include "game/state/pause-menu.hpp"
  21. #include "game/state/nest-selection.hpp"
  22. #include "game/ant/swarm.hpp"
  23. #include "entity/archetype.hpp"
  24. #include "game/system/camera.hpp"
  25. #include "game/system/astronomy.hpp"
  26. #include "game/system/atmosphere.hpp"
  27. #include "game/system/collision.hpp"
  28. #include "game/component/locomotion.hpp"
  29. #include "game/component/transform.hpp"
  30. #include "game/component/terrain.hpp"
  31. #include "game/component/camera.hpp"
  32. #include "game/component/model.hpp"
  33. #include "game/component/constraint/constraint.hpp"
  34. #include "game/component/constraint-stack.hpp"
  35. #include "game/component/steering.hpp"
  36. #include "game/component/picking.hpp"
  37. #include "game/component/spring.hpp"
  38. #include "math/projection.hpp"
  39. #include "game/controls.hpp"
  40. #include "entity/commands.hpp"
  41. #include "animation/screen-transition.hpp"
  42. #include "animation/ease.hpp"
  43. #include "resources/resource-manager.hpp"
  44. #include "game/world.hpp"
  45. #include "application.hpp"
  46. #include "render/passes/clear-pass.hpp"
  47. #include "render/passes/ground-pass.hpp"
  48. #include "state-machine.hpp"
  49. #include "config.hpp"
  50. #include "math/interpolation.hpp"
  51. #include "physics/light/exposure.hpp"
  52. #include "color/color.hpp"
  53. #include "application.hpp"
  54. #include "input/mouse.hpp"
  55. namespace game {
  56. namespace state {
  57. nuptial_flight::nuptial_flight(game::context& ctx):
  58. game::state::base(ctx)
  59. {
  60. debug::log::trace("Entering nuptial flight state...");
  61. // Init selected picking flag
  62. selected_picking_flag = std::uint32_t{1} << (sizeof(std::uint32_t) * 8 - 1);
  63. selected_eid = entt::null;
  64. // Disable UI color clear
  65. ctx.ui_clear_pass->set_cleared_buffers(false, true, false);
  66. // Create world if not yet created
  67. if (ctx.entities.find("earth") == ctx.entities.end())
  68. {
  69. // Create cosmos
  70. game::world::cosmogenesis(ctx);
  71. // Create observer
  72. game::world::create_observer(ctx);
  73. }
  74. // Set world time
  75. game::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
  76. // Set world time scale
  77. game::world::set_time_scale(ctx, 0.0);
  78. // Setup and enable sky and ground passes
  79. ctx.sky_pass->set_enabled(true);
  80. ctx.ground_pass->set_enabled(true);
  81. // Create mating swarm
  82. swarm_eid = game::ant::create_swarm(ctx);
  83. // Switch to surface camera
  84. ctx.underground_camera->set_active(false);
  85. ctx.surface_camera->set_active(true);
  86. // Set camera exposure
  87. const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
  88. ctx.surface_camera->set_exposure(ev100_sunny16);
  89. const auto& viewport_size = ctx.app->get_viewport_size();
  90. const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
  91. // Init camera rig params
  92. camera_rig_near_distance = 1.0f;
  93. camera_rig_far_distance = 150.0f;
  94. camera_rig_near_fov = math::vertical_fov(math::radians(100.0f), aspect_ratio);
  95. camera_rig_far_fov = math::vertical_fov(math::radians(60.0f), aspect_ratio);
  96. camera_rig_zoom_speed = 4.0f;
  97. camera_rig_translation_spring_angular_frequency = period_to_rads(0.125f);
  98. camera_rig_rotation_spring_angular_frequency = period_to_rads(0.125f);
  99. camera_rig_fov_spring_angular_frequency = period_to_rads(0.125f);
  100. camera_rig_focus_ease_to_duration = 1.0f;
  101. // Create camera rig
  102. create_camera_rig();
  103. // Select random alate
  104. ctx.entity_registry->view<component::transform, component::steering>().each
  105. (
  106. [&](entity::id alate_eid, auto& transform, auto& steering)
  107. {
  108. select_entity(alate_eid);
  109. }
  110. );
  111. // Satisfy camera rig constraints
  112. satisfy_camera_rig_constraints();
  113. // Queue fade in
  114. ctx.fade_transition_color->set_value({1, 1, 1});
  115. ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition, config::nuptial_flight_fade_in_duration, true, ease<float>::out_sine, true, nullptr));
  116. // Queue control setup
  117. ctx.function_queue.push(std::bind(&nuptial_flight::enable_controls, this));
  118. debug::log::trace("Entered nuptial flight state");
  119. }
  120. nuptial_flight::~nuptial_flight()
  121. {
  122. debug::log::trace("Exiting nuptial flight state...");
  123. // Deselect selected entity
  124. select_entity(entt::null);
  125. destroy_camera_rig();
  126. game::ant::destroy_swarm(ctx, swarm_eid);
  127. debug::log::trace("Exited nuptial flight state");
  128. }
  129. void nuptial_flight::create_camera_rig()
  130. {
  131. // Construct camera rig focus ease to constraint
  132. component::constraint::ease_to camera_rig_focus_ease_to;
  133. camera_rig_focus_ease_to.target = selected_eid;
  134. camera_rig_focus_ease_to.start = {0, 0, 0};
  135. camera_rig_focus_ease_to.duration = camera_rig_focus_ease_to_duration;
  136. camera_rig_focus_ease_to.t = camera_rig_focus_ease_to.duration;
  137. camera_rig_focus_ease_to.function = &ease<float3, float>::out_expo;
  138. component::constraint_stack_node camera_rig_focus_ease_to_node;
  139. camera_rig_focus_ease_to_node.active = true;
  140. camera_rig_focus_ease_to_node.weight = 1.0f;
  141. camera_rig_focus_ease_to_node.next = entt::null;
  142. camera_rig_focus_ease_to_eid = ctx.entity_registry->create();
  143. ctx.entity_registry->emplace<component::constraint::ease_to>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to);
  144. ctx.entity_registry->emplace<component::constraint_stack_node>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to_node);
  145. // Construct camera rig focus constraint stack
  146. component::constraint_stack camera_rig_focus_constraint_stack;
  147. camera_rig_focus_constraint_stack.priority = 1;
  148. camera_rig_focus_constraint_stack.head = camera_rig_focus_ease_to_eid;
  149. // Construct camera rig focus transform component
  150. component::transform camera_rig_focus_transform;
  151. camera_rig_focus_transform.local = math::transform<float>::identity;
  152. camera_rig_focus_transform.world = camera_rig_focus_transform.local;
  153. camera_rig_focus_transform.warp = true;
  154. // Construct camera rig focus entity
  155. camera_rig_focus_eid = ctx.entity_registry->create();
  156. ctx.entity_registry->emplace<component::transform>(camera_rig_focus_eid, camera_rig_focus_transform);
  157. ctx.entity_registry->emplace<component::constraint_stack>(camera_rig_focus_eid, camera_rig_focus_constraint_stack);
  158. // Construct camera rig pivot constraint
  159. component::constraint::pivot camera_rig_pivot;
  160. camera_rig_pivot.target = camera_rig_focus_eid;
  161. camera_rig_pivot.offset = {0, 0, 0};
  162. component::constraint_stack_node camera_rig_pivot_node;
  163. camera_rig_pivot_node.active = true;
  164. camera_rig_pivot_node.weight = 1.0f;
  165. camera_rig_pivot_node.next = entt::null;
  166. camera_rig_pivot_eid = ctx.entity_registry->create();
  167. ctx.entity_registry->emplace<component::constraint::pivot>(camera_rig_pivot_eid, camera_rig_pivot);
  168. ctx.entity_registry->emplace<component::constraint_stack_node>(camera_rig_pivot_eid, camera_rig_pivot_node);
  169. // Construct camera rig copy translation constraint
  170. component::constraint::copy_translation camera_rig_copy_translation;
  171. camera_rig_copy_translation.target = camera_rig_focus_eid;
  172. camera_rig_copy_translation.copy_x = true;
  173. camera_rig_copy_translation.copy_y = true;
  174. camera_rig_copy_translation.copy_z = true;
  175. camera_rig_copy_translation.invert_x = false;
  176. camera_rig_copy_translation.invert_y = false;
  177. camera_rig_copy_translation.invert_z = false;
  178. camera_rig_copy_translation.offset = true;
  179. component::constraint_stack_node camera_rig_copy_translation_node;
  180. camera_rig_copy_translation_node.active = true;
  181. camera_rig_copy_translation_node.weight = 1.0f;
  182. camera_rig_copy_translation_node.next = camera_rig_pivot_eid;
  183. camera_rig_copy_translation_eid = ctx.entity_registry->create();
  184. ctx.entity_registry->emplace<component::constraint::copy_translation>(camera_rig_copy_translation_eid, camera_rig_copy_translation);
  185. ctx.entity_registry->emplace<component::constraint_stack_node>(camera_rig_copy_translation_eid, camera_rig_copy_translation_node);
  186. // Construct camera rig spring rotation constraint
  187. component::constraint::spring_rotation camera_rig_spring_rotation;
  188. camera_rig_spring_rotation.spring =
  189. {
  190. {0.0f, 0.0f, 0.0f},
  191. {0.0f, 0.0f, 0.0f},
  192. {0.0f, 0.0f, 0.0f},
  193. 1.0f,
  194. camera_rig_rotation_spring_angular_frequency
  195. };
  196. component::constraint_stack_node camera_rig_spring_rotation_node;
  197. camera_rig_spring_rotation_node.active = true;
  198. camera_rig_spring_rotation_node.weight = 1.0f;
  199. camera_rig_spring_rotation_node.next = camera_rig_copy_translation_eid;
  200. camera_rig_spring_rotation_eid = ctx.entity_registry->create();
  201. ctx.entity_registry->emplace<component::constraint::spring_rotation>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation);
  202. ctx.entity_registry->emplace<component::constraint_stack_node>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation_node);
  203. // Construct camera rig spring translation constraint
  204. component::constraint::spring_translation camera_rig_spring_translation;
  205. camera_rig_spring_translation.spring =
  206. {
  207. {0.0f, 0.0f, 0.0f},
  208. {0.0f, 0.0f, 0.0f},
  209. {0.0f, 0.0f, 0.0f},
  210. 1.0f,
  211. camera_rig_translation_spring_angular_frequency
  212. };
  213. component::constraint_stack_node camera_rig_spring_translation_node;
  214. camera_rig_spring_translation_node.active = true;
  215. camera_rig_spring_translation_node.weight = 1.0f;
  216. camera_rig_spring_translation_node.next = camera_rig_spring_rotation_eid;
  217. camera_rig_spring_translation_eid = ctx.entity_registry->create();
  218. ctx.entity_registry->emplace<component::constraint::spring_translation>(camera_rig_spring_translation_eid, camera_rig_spring_translation);
  219. ctx.entity_registry->emplace<component::constraint_stack_node>(camera_rig_spring_translation_eid, camera_rig_spring_translation_node);
  220. // Construct camera rig constraint stack
  221. component::constraint_stack camera_rig_constraint_stack;
  222. camera_rig_constraint_stack.priority = 2;
  223. camera_rig_constraint_stack.head = camera_rig_spring_translation_eid;
  224. // Construct camera rig transform component
  225. component::transform camera_rig_transform;
  226. camera_rig_transform.local = math::transform<float>::identity;
  227. camera_rig_transform.world = camera_rig_transform.local;
  228. camera_rig_transform.warp = true;
  229. // Construct camera rig camera component
  230. component::camera camera_rig_camera;
  231. camera_rig_camera.object = ctx.surface_camera;
  232. // Construct camera rig entity
  233. camera_rig_eid = ctx.entity_registry->create();
  234. ctx.entity_registry->emplace<component::camera>(camera_rig_eid, camera_rig_camera);
  235. ctx.entity_registry->emplace<component::transform>(camera_rig_eid, camera_rig_transform);
  236. ctx.entity_registry->emplace<component::constraint_stack>(camera_rig_eid, camera_rig_constraint_stack);
  237. // Construct camera rig fov spring
  238. component::spring1 camera_rig_fov_spring;
  239. camera_rig_fov_spring.spring =
  240. {
  241. 0.0f,
  242. 0.0f,
  243. 0.0f,
  244. 1.0f,
  245. camera_rig_fov_spring_angular_frequency
  246. };
  247. camera_rig_fov_spring.callback = [&](float fov)
  248. {
  249. ctx.surface_camera->set_perspective(fov, ctx.surface_camera->get_aspect_ratio(), ctx.surface_camera->get_clip_near(), ctx.surface_camera->get_clip_far());
  250. };
  251. // Construct camera rig fov spring entity
  252. camera_rig_fov_spring_eid = ctx.entity_registry->create();
  253. ctx.entity_registry->emplace<component::spring1>(camera_rig_fov_spring_eid, camera_rig_fov_spring);
  254. set_camera_rig_zoom(0.25f);
  255. }
  256. void nuptial_flight::destroy_camera_rig()
  257. {
  258. ctx.entity_registry->destroy(camera_rig_eid);
  259. ctx.entity_registry->destroy(camera_rig_spring_translation_eid);
  260. ctx.entity_registry->destroy(camera_rig_spring_rotation_eid);
  261. ctx.entity_registry->destroy(camera_rig_copy_translation_eid);
  262. ctx.entity_registry->destroy(camera_rig_pivot_eid);
  263. ctx.entity_registry->destroy(camera_rig_focus_eid);
  264. ctx.entity_registry->destroy(camera_rig_focus_ease_to_eid);
  265. ctx.entity_registry->destroy(camera_rig_fov_spring_eid);
  266. }
  267. void nuptial_flight::set_camera_rig_zoom(float zoom)
  268. {
  269. camera_rig_zoom = zoom;
  270. const float distance = math::log_lerp(camera_rig_far_distance, camera_rig_near_distance, camera_rig_zoom);
  271. ctx.entity_registry->patch<component::constraint::spring_translation>
  272. (
  273. camera_rig_spring_translation_eid,
  274. [&](auto& component)
  275. {
  276. component.spring.x1[2] = distance;
  277. }
  278. );
  279. const float fov = math::log_lerp(camera_rig_far_fov, camera_rig_near_fov, camera_rig_zoom);
  280. ctx.entity_registry->patch<component::spring1>
  281. (
  282. camera_rig_fov_spring_eid,
  283. [&](auto& component)
  284. {
  285. component.spring.x1 = fov;
  286. }
  287. );
  288. }
  289. void nuptial_flight::satisfy_camera_rig_constraints()
  290. {
  291. // Satisfy camera rig focus ease to constraint
  292. ctx.entity_registry->patch<component::constraint::ease_to>
  293. (
  294. camera_rig_focus_ease_to_eid,
  295. [&](auto& component)
  296. {
  297. component.t = component.duration;
  298. }
  299. );
  300. // Satisfy camera rig spring translation constraint
  301. ctx.entity_registry->patch<component::constraint::spring_translation>
  302. (
  303. camera_rig_spring_translation_eid,
  304. [&](auto& component)
  305. {
  306. component.spring.x0 = component.spring.x1;
  307. component.spring.v *= 0.0f;
  308. }
  309. );
  310. // Satisfy camera rig spring rotation constraint
  311. ctx.entity_registry->patch<component::constraint::spring_rotation>
  312. (
  313. camera_rig_spring_rotation_eid,
  314. [&](auto& component)
  315. {
  316. component.spring.x0 = component.spring.x1;
  317. component.spring.v *= 0.0f;
  318. }
  319. );
  320. // Satisfycamera rig fov spring
  321. ctx.entity_registry->patch<component::spring1>
  322. (
  323. camera_rig_fov_spring_eid,
  324. [&](auto& component)
  325. {
  326. component.spring.x0 = component.spring.x1;
  327. component.spring.v *= 0.0f;
  328. }
  329. );
  330. }
  331. void nuptial_flight::enable_controls()
  332. {
  333. /*
  334. // Reset mouse look
  335. mouse_look = false;
  336. double time_scale = 0.0;
  337. double ff_time_scale = 60.0 * 200.0;
  338. // Init control settings
  339. float mouse_tilt_sensitivity = 1.0f;
  340. float mouse_pan_sensitivity = 1.0f;
  341. bool mouse_invert_tilt = false;
  342. bool mouse_invert_pan = false;
  343. bool mouse_look_toggle = false;
  344. float gamepad_tilt_sensitivity = 1.0f;
  345. float gamepad_pan_sensitivity = 1.0f;
  346. bool gamepad_invert_tilt = false;
  347. bool gamepad_invert_pan = false;
  348. // Read control settings
  349. if (ctx.config->contains("mouse_tilt_sensitivity"))
  350. mouse_tilt_sensitivity = math::radians((*ctx.config)["mouse_tilt_sensitivity"].get<float>());
  351. if (ctx.config->contains("mouse_pan_sensitivity"))
  352. mouse_pan_sensitivity = math::radians((*ctx.config)["mouse_pan_sensitivity"].get<float>());
  353. if (ctx.config->contains("mouse_invert_tilt"))
  354. mouse_invert_tilt = (*ctx.config)["mouse_invert_tilt"].get<bool>();
  355. if (ctx.config->contains("mouse_invert_pan"))
  356. mouse_invert_pan = (*ctx.config)["mouse_invert_pan"].get<bool>();
  357. if (ctx.config->contains("mouse_look_toggle"))
  358. mouse_look_toggle = (*ctx.config)["mouse_look_toggle"].get<bool>();
  359. if (ctx.config->contains("gamepad_tilt_sensitivity"))
  360. gamepad_tilt_sensitivity = math::radians((*ctx.config)["gamepad_tilt_sensitivity"].get<float>());
  361. if (ctx.config->contains("gamepad_pan_sensitivity"))
  362. gamepad_pan_sensitivity = math::radians((*ctx.config)["gamepad_pan_sensitivity"].get<float>());
  363. if (ctx.config->contains("gamepad_invert_tilt"))
  364. gamepad_invert_tilt = (*ctx.config)["gamepad_invert_tilt"].get<bool>();
  365. if (ctx.config->contains("gamepad_invert_pan"))
  366. gamepad_invert_pan = (*ctx.config)["gamepad_invert_pan"].get<bool>();
  367. // Determine tilt and pan factors according to sensitivity and inversion
  368. const float mouse_tilt_factor = mouse_tilt_sensitivity * (mouse_invert_tilt ? -1.0f : 1.0f);
  369. const float mouse_pan_factor = mouse_pan_sensitivity * (mouse_invert_pan ? -1.0f : 1.0f);
  370. const float gamepad_tilt_factor = gamepad_tilt_sensitivity * (gamepad_invert_tilt ? -1.0f : 1.0f);
  371. const float gamepad_pan_factor = gamepad_pan_sensitivity * (gamepad_invert_pan ? -1.0f : 1.0f);
  372. // Mouse look
  373. ctx.controls["mouse_look"]->set_activated_callback
  374. (
  375. [&, mouse_look_toggle]()
  376. {
  377. if (mouse_look_toggle)
  378. mouse_look = !mouse_look;
  379. else
  380. mouse_look = true;
  381. ctx.app->set_relative_mouse_mode(mouse_look);
  382. }
  383. );
  384. ctx.controls["mouse_look"]->set_deactivated_callback
  385. (
  386. [&, mouse_look_toggle]()
  387. {
  388. if (!mouse_look_toggle && mouse_look)
  389. {
  390. mouse_look = false;
  391. ctx.app->set_relative_mouse_mode(false);
  392. }
  393. }
  394. );
  395. // Arc left control
  396. ctx.controls["look_right_mouse"]->set_active_callback
  397. (
  398. [&, mouse_pan_factor](float value)
  399. {
  400. if (!mouse_look)
  401. return;
  402. ctx.entity_registry->patch<component::constraint::spring_rotation>
  403. (
  404. camera_rig_spring_rotation_eid,
  405. [&, mouse_pan_factor](auto& component)
  406. {
  407. component.spring.x1[0] -= mouse_pan_factor * value;
  408. }
  409. );
  410. }
  411. );
  412. ctx.controls["look_right_gamepad"]->set_active_callback
  413. (
  414. [&, gamepad_pan_factor](float value)
  415. {
  416. ctx.entity_registry->patch<component::constraint::spring_rotation>
  417. (
  418. camera_rig_spring_rotation_eid,
  419. [&, gamepad_pan_factor](auto& component)
  420. {
  421. component.spring.x1[0] -= gamepad_pan_factor * value * static_cast<float>(ctx.loop.get_update_period());
  422. }
  423. );
  424. }
  425. );
  426. // Arc right control
  427. ctx.controls["look_left_mouse"]->set_active_callback
  428. (
  429. [&, mouse_pan_factor](float value)
  430. {
  431. if (!mouse_look)
  432. return;
  433. ctx.entity_registry->patch<component::constraint::spring_rotation>
  434. (
  435. camera_rig_spring_rotation_eid,
  436. [&, mouse_pan_factor](auto& component)
  437. {
  438. component.spring.x1[0] += mouse_pan_factor * value;
  439. }
  440. );
  441. }
  442. );
  443. ctx.controls["look_left_gamepad"]->set_active_callback
  444. (
  445. [&, gamepad_pan_factor](float value)
  446. {
  447. ctx.entity_registry->patch<component::constraint::spring_rotation>
  448. (
  449. camera_rig_spring_rotation_eid,
  450. [&, gamepad_pan_factor](auto& component)
  451. {
  452. component.spring.x1[0] += gamepad_pan_factor * value * static_cast<float>(ctx.loop.get_update_period());
  453. }
  454. );
  455. }
  456. );
  457. // Arc down control
  458. ctx.controls["look_up_mouse"]->set_active_callback
  459. (
  460. [&, mouse_tilt_factor](float value)
  461. {
  462. if (!mouse_look)
  463. return;
  464. ctx.entity_registry->patch<component::constraint::spring_rotation>
  465. (
  466. camera_rig_spring_rotation_eid,
  467. [&, mouse_tilt_factor](auto& component)
  468. {
  469. component.spring.x1[1] -= mouse_tilt_factor * value;
  470. component.spring.x1[1] = std::max(-math::half_pi<float>, component.spring.x1[1]);
  471. }
  472. );
  473. }
  474. );
  475. ctx.controls["look_up_gamepad"]->set_active_callback
  476. (
  477. [&, gamepad_tilt_factor](float value)
  478. {
  479. ctx.entity_registry->patch<component::constraint::spring_rotation>
  480. (
  481. camera_rig_spring_rotation_eid,
  482. [&, gamepad_tilt_factor](auto& component)
  483. {
  484. component.spring.x1[1] -= gamepad_tilt_factor * value * static_cast<float>(ctx.loop.get_update_period());
  485. component.spring.x1[1] = std::max(-math::half_pi<float>, component.spring.x1[1]);
  486. }
  487. );
  488. }
  489. );
  490. // Arc up control
  491. ctx.controls["look_down_mouse"]->set_active_callback
  492. (
  493. [&, mouse_tilt_factor](float value)
  494. {
  495. if (!mouse_look)
  496. return;
  497. ctx.entity_registry->patch<component::constraint::spring_rotation>
  498. (
  499. camera_rig_spring_rotation_eid,
  500. [&, mouse_tilt_factor](auto& component)
  501. {
  502. component.spring.x1[1] += mouse_tilt_factor * value;
  503. component.spring.x1[1] = std::min(math::half_pi<float>, component.spring.x1[1]);
  504. }
  505. );
  506. }
  507. );
  508. ctx.controls["look_down_gamepad"]->set_active_callback
  509. (
  510. [&, gamepad_tilt_factor](float value)
  511. {
  512. ctx.entity_registry->patch<component::constraint::spring_rotation>
  513. (
  514. camera_rig_spring_rotation_eid,
  515. [&, gamepad_tilt_factor](auto& component)
  516. {
  517. component.spring.x1[1] += gamepad_tilt_factor * value * static_cast<float>(ctx.loop.get_update_period());
  518. component.spring.x1[1] = std::min(math::half_pi<float>, component.spring.x1[1]);
  519. }
  520. );
  521. }
  522. );
  523. // Dolly in control
  524. ctx.controls["move_up"]->set_active_callback
  525. (
  526. [&](float value)
  527. {
  528. set_camera_rig_zoom(std::min(1.0f, camera_rig_zoom + camera_rig_zoom_speed * static_cast<float>(ctx.loop.get_update_period())));
  529. }
  530. );
  531. // Dolly out control
  532. ctx.controls["move_down"]->set_active_callback
  533. (
  534. [&](float value)
  535. {
  536. set_camera_rig_zoom(std::max(0.0f, camera_rig_zoom - camera_rig_zoom_speed * static_cast<float>(ctx.loop.get_update_period())));
  537. }
  538. );
  539. // Mouse select control
  540. ctx.controls["select_mouse"]->set_activated_callback
  541. (
  542. [&]()
  543. {
  544. // Get window-space mouse coordinates
  545. auto [mouse_x, mouse_y] = ctx.app->get_mouse()->get_current_position();
  546. // Get window viewport size
  547. const auto viewport_size = ctx.app->viewport_size();
  548. // Transform mouse coordinates from window space to NDC space
  549. const float2 mouse_ndc =
  550. {
  551. static_cast<float>(mouse_x) / static_cast<float>(viewport_size[0] - 1) * 2.0f - 1.0f,
  552. (1.0f - static_cast<float>(mouse_y) / static_cast<float>(viewport_size[1] - 1)) * 2.0f - 1.0f
  553. };
  554. // Get picking ray from camera
  555. const geom::primitive::ray<float, 3> ray = ctx.surface_camera->pick(mouse_ndc);
  556. // Pick entity
  557. entity::id picked_eid = ctx.collision_system->pick_nearest(ray, ~selected_picking_flag);
  558. if (picked_eid != entt::null)
  559. {
  560. select_entity(picked_eid);
  561. }
  562. }
  563. );
  564. // Select forward control
  565. ctx.controls["move_forward"]->set_activated_callback
  566. (
  567. [&]()
  568. {
  569. select_nearest_entity({0.0f, 0.0f, -1.0f});
  570. }
  571. );
  572. // Select back control
  573. ctx.controls["move_back"]->set_activated_callback
  574. (
  575. [&]()
  576. {
  577. select_nearest_entity({0.0f, 0.0f, 1.0f});
  578. }
  579. );
  580. // Select right control
  581. ctx.controls["move_right"]->set_activated_callback
  582. (
  583. [&]()
  584. {
  585. select_nearest_entity({1.0f, 0.0f, 0.0f});
  586. }
  587. );
  588. // Select left control
  589. ctx.controls["move_left"]->set_activated_callback
  590. (
  591. [&]()
  592. {
  593. select_nearest_entity({-1.0f, 0.0f, 0.0f});
  594. }
  595. );
  596. // Action control
  597. ctx.controls["action"]->set_activated_callback
  598. (
  599. [&]()
  600. {
  601. // Disable controls
  602. disable_controls();
  603. // Change to nest selection state
  604. ctx.state_machine.pop();
  605. ctx.state_machine.emplace(new game::state::nest_selection(ctx));
  606. }
  607. );
  608. // Fast-forward
  609. ctx.controls["fast_forward"]->set_activated_callback
  610. (
  611. [&ctx = this->ctx, ff_time_scale]()
  612. {
  613. game::world::set_time_scale(ctx, ff_time_scale);
  614. }
  615. );
  616. ctx.controls["fast_forward"]->set_deactivated_callback
  617. (
  618. [&ctx = this->ctx, time_scale]()
  619. {
  620. game::world::set_time_scale(ctx, time_scale);
  621. }
  622. );
  623. ctx.controls["rewind"]->set_activated_callback
  624. (
  625. [&ctx = this->ctx, ff_time_scale]()
  626. {
  627. game::world::set_time_scale(ctx, -ff_time_scale);
  628. }
  629. );
  630. ctx.controls["rewind"]->set_deactivated_callback
  631. (
  632. [&ctx = this->ctx, time_scale]()
  633. {
  634. game::world::set_time_scale(ctx, time_scale);
  635. }
  636. );
  637. // Setup pause control
  638. ctx.controls["pause"]->set_activated_callback
  639. (
  640. [this, &ctx = this->ctx]()
  641. {
  642. // Disable controls
  643. this->disable_controls();
  644. // Set resume callback
  645. ctx.resume_callback = [this, &ctx]()
  646. {
  647. this->enable_controls();
  648. ctx.resume_callback = nullptr;
  649. };
  650. // Push pause menu state
  651. ctx.state_machine.emplace(new game::state::pause_menu(ctx));
  652. }
  653. );
  654. ctx.controls["increase_exposure"]->set_active_callback
  655. (
  656. [&ctx = this->ctx](float)
  657. {
  658. //ctx.astronomy_system->set_exposure_offset(ctx.astronomy_system->get_exposure_offset() - 1.0f);
  659. ctx.surface_camera->set_exposure(ctx.surface_camera->get_exposure() + 3.0f * static_cast<float>(ctx.loop.get_update_period()));
  660. debug::log::info("EV100: " + std::to_string(ctx.surface_camera->get_exposure()));
  661. }
  662. );
  663. ctx.controls["decrease_exposure"]->set_active_callback
  664. (
  665. [&ctx = this->ctx](float)
  666. {
  667. //ctx.astronomy_system->set_exposure_offset(ctx.astronomy_system->get_exposure_offset() + 1.0f);
  668. ctx.surface_camera->set_exposure(ctx.surface_camera->get_exposure() - 3.0f * static_cast<float>(ctx.loop.get_update_period()));
  669. debug::log::info("EV100: " + std::to_string(ctx.surface_camera->get_exposure()));
  670. }
  671. );
  672. */
  673. }
  674. void nuptial_flight::disable_controls()
  675. {
  676. /*
  677. if (mouse_look)
  678. {
  679. mouse_look = false;
  680. ctx.app->set_relative_mouse_mode(false);
  681. }
  682. ctx.controls["mouse_look"]->set_activated_callback(nullptr);
  683. ctx.controls["mouse_look"]->set_deactivated_callback(nullptr);
  684. ctx.controls["look_right_mouse"]->set_active_callback(nullptr);
  685. ctx.controls["look_right_gamepad"]->set_active_callback(nullptr);
  686. ctx.controls["look_left_mouse"]->set_active_callback(nullptr);
  687. ctx.controls["look_left_gamepad"]->set_active_callback(nullptr);
  688. ctx.controls["look_up_mouse"]->set_active_callback(nullptr);
  689. ctx.controls["look_up_gamepad"]->set_active_callback(nullptr);
  690. ctx.controls["look_down_mouse"]->set_active_callback(nullptr);
  691. ctx.controls["look_down_gamepad"]->set_active_callback(nullptr);
  692. ctx.controls["move_up"]->set_active_callback(nullptr);
  693. ctx.controls["move_down"]->set_active_callback(nullptr);
  694. ctx.controls["select_mouse"]->set_activated_callback(nullptr);
  695. ctx.controls["move_forward"]->set_activated_callback(nullptr);
  696. ctx.controls["move_back"]->set_activated_callback(nullptr);
  697. ctx.controls["move_right"]->set_activated_callback(nullptr);
  698. ctx.controls["move_left"]->set_activated_callback(nullptr);
  699. ctx.controls["action"]->set_activated_callback(nullptr);
  700. ctx.controls["fast_forward"]->set_activated_callback(nullptr);
  701. ctx.controls["fast_forward"]->set_deactivated_callback(nullptr);
  702. ctx.controls["rewind"]->set_activated_callback(nullptr);
  703. ctx.controls["rewind"]->set_deactivated_callback(nullptr);
  704. ctx.controls["pause"]->set_activated_callback(nullptr);
  705. ctx.controls["increase_exposure"]->set_active_callback(nullptr);
  706. ctx.controls["decrease_exposure"]->set_active_callback(nullptr);
  707. */
  708. }
  709. void nuptial_flight::select_entity(entity::id entity_id)
  710. {
  711. if (entity_id != selected_eid)
  712. {
  713. if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<component::picking>(selected_eid))
  714. {
  715. // Unset selected bit on picking flags of previously selected entity
  716. ctx.entity_registry->patch<component::picking>
  717. (
  718. selected_eid,
  719. [&](auto& component)
  720. {
  721. component.flags &= ~selected_picking_flag;
  722. }
  723. );
  724. }
  725. selected_eid = entity_id;
  726. if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<component::picking>(selected_eid))
  727. {
  728. // Set selected bit on picking flags of current selected entity
  729. ctx.entity_registry->patch<component::picking>
  730. (
  731. selected_eid,
  732. [&](auto& component)
  733. {
  734. component.flags |= selected_picking_flag;
  735. }
  736. );
  737. }
  738. // Update camera rig focus ease to target
  739. ctx.entity_registry->patch<component::constraint::ease_to>
  740. (
  741. camera_rig_focus_ease_to_eid,
  742. [&](auto& component)
  743. {
  744. component.target = selected_eid;
  745. component.t = 0.0f;
  746. const component::transform* transform = ctx.entity_registry->try_get<component::transform>(camera_rig_focus_eid);
  747. if (transform)
  748. component.start = transform->world.translation;
  749. }
  750. );
  751. }
  752. }
  753. void nuptial_flight::select_nearest_entity(const float3& direction)
  754. {
  755. if (!ctx.entity_registry->valid(selected_eid))
  756. return;
  757. const component::transform* selected_eid_transform = ctx.entity_registry->try_get<component::transform>(selected_eid);
  758. if (!selected_eid_transform)
  759. return;
  760. // Construct picking plane
  761. const float3 picking_normal = math::normalize(ctx.surface_camera->get_rotation() * direction);
  762. const float3 picking_origin = selected_eid_transform->world.translation;
  763. // Pick entity
  764. entity::id picked_eid = ctx.collision_system->pick_nearest(picking_origin, picking_normal, ~selected_picking_flag);
  765. if (picked_eid != entt::null)
  766. {
  767. select_entity(picked_eid);
  768. }
  769. }
  770. } // namespace state
  771. } // namespace game