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

955 lines
30 KiB

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