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

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