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

489 lines
17 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/states/nuptial-flight-state.hpp"
  20. #include "game/states/pause-menu-state.hpp"
  21. #include "game/states/nest-selection-state.hpp"
  22. #include "game/ant/ant-swarm.hpp"
  23. #include <engine/entity/archetype.hpp>
  24. #include "game/systems/camera-system.hpp"
  25. #include "game/systems/astronomy-system.hpp"
  26. #include "game/systems/atmosphere-system.hpp"
  27. #include "game/systems/collision-system.hpp"
  28. #include "game/components/ant-caste-component.hpp"
  29. #include "game/components/transform-component.hpp"
  30. #include "game/components/terrain-component.hpp"
  31. #include "game/components/name-component.hpp"
  32. #include "game/components/constraint-stack-component.hpp"
  33. #include "game/components/steering-component.hpp"
  34. #include "game/components/picking-component.hpp"
  35. #include "game/components/scene-component.hpp"
  36. #include "game/constraints/child-of-constraint.hpp"
  37. #include "game/constraints/copy-rotation-constraint.hpp"
  38. #include "game/constraints/copy-scale-constraint.hpp"
  39. #include "game/constraints/copy-transform-constraint.hpp"
  40. #include "game/constraints/copy-translation-constraint.hpp"
  41. #include "game/constraints/ease-to-constraint.hpp"
  42. #include "game/constraints/pivot-constraint.hpp"
  43. #include "game/constraints/spring-rotation-constraint.hpp"
  44. #include "game/constraints/spring-to-constraint.hpp"
  45. #include "game/constraints/spring-translation-constraint.hpp"
  46. #include "game/constraints/three-dof-constraint.hpp"
  47. #include "game/constraints/track-to-constraint.hpp"
  48. #include <engine/math/projection.hpp>
  49. #include "game/controls.hpp"
  50. #include "game/commands/commands.hpp"
  51. #include <engine/animation/screen-transition.hpp>
  52. #include <engine/animation/ease.hpp>
  53. #include <engine/resources/resource-manager.hpp>
  54. #include "game/world.hpp"
  55. #include "game/strings.hpp"
  56. #include <engine/utility/state-machine.hpp>
  57. #include <engine/config.hpp>
  58. #include <engine/math/interpolation.hpp>
  59. #include <engine/physics/light/exposure.hpp>
  60. #include <engine/color/color.hpp>
  61. #include <engine/input/mouse.hpp>
  62. #include <engine/utility/hash/fnv1a.hpp>
  63. #include <random>
  64. using namespace hash::literals;
  65. nuptial_flight_state::nuptial_flight_state(::game& ctx):
  66. game_state(ctx)
  67. {
  68. debug::log_trace("Entering nuptial flight state...");
  69. // Init selected picking flag
  70. selected_picking_flag = std::uint32_t{1} << (sizeof(std::uint32_t) * 8 - 1);
  71. selected_eid = entt::null;
  72. // Create world if not yet created
  73. if (ctx.entities.find("earth") == ctx.entities.end())
  74. {
  75. // Create cosmos
  76. ::world::cosmogenesis(ctx);
  77. // Create observer
  78. ::world::create_observer(ctx);
  79. }
  80. ::world::enter_ecoregion(ctx, *ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco"));
  81. // Set world time
  82. ::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
  83. // Set world time scale
  84. ::world::set_time_scale(ctx, 0.0);
  85. // Setup and enable sky and ground passes
  86. ctx.sky_pass->set_enabled(true);
  87. // Create mating swarm
  88. swarm_eid = create_ant_swarm(ctx);
  89. // Load name pool
  90. name_pool = ctx.resource_manager->load<text_file>("name-pool-en.txt");
  91. // Assign random ant names
  92. std::uniform_int_distribution<> name_pool_distribution(0, static_cast<int>(name_pool->lines.size() - 1));
  93. ctx.entity_registry->view<ant_caste_component>().each
  94. (
  95. [&](entity::id entity_id, const auto& caste)
  96. {
  97. ctx.entity_registry->emplace_or_replace<name_component>
  98. (
  99. entity_id,
  100. name_pool->lines[name_pool_distribution(ctx.rng)]
  101. );
  102. }
  103. );
  104. // Set camera exposure
  105. const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
  106. ctx.surface_camera->set_exposure_value(ev100_sunny16);
  107. const auto& viewport_size = ctx.window->get_viewport_size();
  108. const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
  109. // Init camera rig params
  110. camera_rig_near_distance = 1.0f;
  111. camera_rig_far_distance = 150.0f;
  112. camera_rig_near_fov = math::vertical_fov(math::radians(100.0f), aspect_ratio);
  113. camera_rig_far_fov = math::vertical_fov(math::radians(60.0f), aspect_ratio);
  114. camera_rig_zoom_speed = 4.0f;
  115. camera_rig_translation_spring_angular_frequency = physics::s_to_rads(0.125f);
  116. camera_rig_rotation_spring_angular_frequency = physics::s_to_rads(0.125f);
  117. camera_rig_fov_spring_angular_frequency = physics::s_to_rads(0.125f);
  118. camera_rig_focus_ease_to_duration = 1.0f;
  119. // Create camera rig
  120. create_camera_rig();
  121. // Construct selection text
  122. selection_text.set_material(ctx.menu_font_material);
  123. selection_text.set_color({1.0f, 1.0f, 1.0f, 1.0f});
  124. selection_text.set_font(&ctx.menu_font);
  125. const auto& text_aabb = selection_text.get_bounds();
  126. float text_w = text_aabb.max.x() - text_aabb.min.x();
  127. float text_h = text_aabb.max.y() - text_aabb.min.y();
  128. selection_text.set_translation({std::round(viewport_size.x() * 0.5f - text_w * 0.5f), std::round(ctx.menu_font.get_font_metrics().size), 0.0f});
  129. // Add text to UI
  130. ctx.ui_scene->add_object(selection_text);
  131. // Select random alate
  132. entity::id random_alate_eid;
  133. ctx.entity_registry->view<transform_component, steering_component>().each
  134. (
  135. [&](entity::id entity_id, auto& transform, auto& steering)
  136. {
  137. random_alate_eid = entity_id;
  138. }
  139. );
  140. select_entity(random_alate_eid);
  141. // Satisfy camera rig constraints
  142. satisfy_camera_rig_constraints();
  143. // Setup controls
  144. setup_controls();
  145. // Queue enable controls
  146. ctx.function_queue.push
  147. (
  148. [&ctx]()
  149. {
  150. ::enable_game_controls(ctx);
  151. }
  152. );
  153. // Queue fade in
  154. ctx.fade_transition_color->set({0, 0, 0});
  155. ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition.get(), 1.0f, true, ease<float>::out_sine, true, nullptr));
  156. // Refresh frame scheduler
  157. ctx.frame_scheduler.refresh();
  158. debug::log_trace("Entered nuptial flight state");
  159. }
  160. nuptial_flight_state::~nuptial_flight_state()
  161. {
  162. debug::log_trace("Exiting nuptial flight state...");
  163. // Disable game controls
  164. ::disable_game_controls(ctx);
  165. // Remove text from UI
  166. ctx.ui_scene->remove_object(selection_text);
  167. // Deselect selected entity
  168. select_entity(entt::null);
  169. destroy_camera_rig();
  170. destroy_ant_swarm(ctx, swarm_eid);
  171. debug::log_trace("Exited nuptial flight state");
  172. }
  173. void nuptial_flight_state::create_camera_rig()
  174. {
  175. // Construct camera rig focus ease to constraint
  176. ease_to_constraint camera_rig_focus_ease_to;
  177. camera_rig_focus_ease_to.target = selected_eid;
  178. camera_rig_focus_ease_to.start = {0, 0, 0};
  179. camera_rig_focus_ease_to.duration = camera_rig_focus_ease_to_duration;
  180. camera_rig_focus_ease_to.t = camera_rig_focus_ease_to.duration;
  181. camera_rig_focus_ease_to.function = &ease<math::fvec3, float>::out_expo;
  182. constraint_stack_node_component camera_rig_focus_ease_to_node;
  183. camera_rig_focus_ease_to_node.active = true;
  184. camera_rig_focus_ease_to_node.weight = 1.0f;
  185. camera_rig_focus_ease_to_node.next = entt::null;
  186. camera_rig_focus_ease_to_eid = ctx.entity_registry->create();
  187. ctx.entity_registry->emplace<ease_to_constraint>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to);
  188. ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to_node);
  189. // Construct camera rig focus constraint stack
  190. constraint_stack_component camera_rig_focus_constraint_stack;
  191. camera_rig_focus_constraint_stack.priority = 1;
  192. camera_rig_focus_constraint_stack.head = camera_rig_focus_ease_to_eid;
  193. // Construct camera rig focus transform component
  194. transform_component camera_rig_focus_transform;
  195. camera_rig_focus_transform.local = math::transform<float>::identity();
  196. camera_rig_focus_transform.world = camera_rig_focus_transform.local;
  197. // Construct camera rig focus entity
  198. camera_rig_focus_eid = ctx.entity_registry->create();
  199. ctx.entity_registry->emplace<transform_component>(camera_rig_focus_eid, camera_rig_focus_transform);
  200. ctx.entity_registry->emplace<constraint_stack_component>(camera_rig_focus_eid, camera_rig_focus_constraint_stack);
  201. // Construct camera rig pivot constraint
  202. pivot_constraint camera_rig_pivot;
  203. camera_rig_pivot.target = camera_rig_focus_eid;
  204. camera_rig_pivot.offset = {0, 0, 0};
  205. constraint_stack_node_component camera_rig_pivot_node;
  206. camera_rig_pivot_node.active = true;
  207. camera_rig_pivot_node.weight = 1.0f;
  208. camera_rig_pivot_node.next = entt::null;
  209. camera_rig_pivot_eid = ctx.entity_registry->create();
  210. ctx.entity_registry->emplace<pivot_constraint>(camera_rig_pivot_eid, camera_rig_pivot);
  211. ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_pivot_eid, camera_rig_pivot_node);
  212. // Construct camera rig copy translation constraint
  213. copy_translation_constraint camera_rig_copy_translation;
  214. camera_rig_copy_translation.target = camera_rig_focus_eid;
  215. camera_rig_copy_translation.copy_x = true;
  216. camera_rig_copy_translation.copy_y = true;
  217. camera_rig_copy_translation.copy_z = true;
  218. camera_rig_copy_translation.invert_x = false;
  219. camera_rig_copy_translation.invert_y = false;
  220. camera_rig_copy_translation.invert_z = false;
  221. camera_rig_copy_translation.offset = true;
  222. constraint_stack_node_component camera_rig_copy_translation_node;
  223. camera_rig_copy_translation_node.active = true;
  224. camera_rig_copy_translation_node.weight = 1.0f;
  225. camera_rig_copy_translation_node.next = camera_rig_pivot_eid;
  226. camera_rig_copy_translation_eid = ctx.entity_registry->create();
  227. ctx.entity_registry->emplace<copy_translation_constraint>(camera_rig_copy_translation_eid, camera_rig_copy_translation);
  228. ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_copy_translation_eid, camera_rig_copy_translation_node);
  229. // Construct camera rig spring rotation constraint
  230. spring_rotation_constraint camera_rig_spring_rotation;
  231. camera_rig_spring_rotation.spring.set_angular_frequency(camera_rig_rotation_spring_angular_frequency);
  232. constraint_stack_node_component camera_rig_spring_rotation_node;
  233. camera_rig_spring_rotation_node.active = true;
  234. camera_rig_spring_rotation_node.weight = 1.0f;
  235. camera_rig_spring_rotation_node.next = camera_rig_copy_translation_eid;
  236. camera_rig_spring_rotation_eid = ctx.entity_registry->create();
  237. ctx.entity_registry->emplace<spring_rotation_constraint>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation);
  238. ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation_node);
  239. // Construct camera rig spring translation constraint
  240. spring_translation_constraint camera_rig_spring_translation;
  241. camera_rig_spring_translation.spring.set_angular_frequency(camera_rig_translation_spring_angular_frequency);
  242. constraint_stack_node_component camera_rig_spring_translation_node;
  243. camera_rig_spring_translation_node.active = true;
  244. camera_rig_spring_translation_node.weight = 1.0f;
  245. camera_rig_spring_translation_node.next = camera_rig_spring_rotation_eid;
  246. camera_rig_spring_translation_eid = ctx.entity_registry->create();
  247. ctx.entity_registry->emplace<spring_translation_constraint>(camera_rig_spring_translation_eid, camera_rig_spring_translation);
  248. ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_spring_translation_eid, camera_rig_spring_translation_node);
  249. // Construct camera rig constraint stack
  250. constraint_stack_component camera_rig_constraint_stack;
  251. camera_rig_constraint_stack.priority = 2;
  252. camera_rig_constraint_stack.head = camera_rig_spring_translation_eid;
  253. // Construct camera rig transform component
  254. transform_component camera_rig_transform;
  255. camera_rig_transform.local = math::transform<float>::identity();
  256. camera_rig_transform.world = camera_rig_transform.local;
  257. // Construct camera rig camera component
  258. scene_component camera_rig_camera;
  259. camera_rig_camera.object = ctx.surface_camera;
  260. // Construct camera rig entity
  261. camera_rig_eid = ctx.entity_registry->create();
  262. ctx.entity_registry->emplace<scene_component>(camera_rig_eid, camera_rig_camera);
  263. ctx.entity_registry->emplace<transform_component>(camera_rig_eid, camera_rig_transform);
  264. ctx.entity_registry->emplace<constraint_stack_component>(camera_rig_eid, camera_rig_constraint_stack);
  265. set_camera_rig_zoom(0.25f);
  266. }
  267. void nuptial_flight_state::destroy_camera_rig()
  268. {
  269. ctx.entity_registry->destroy(camera_rig_eid);
  270. ctx.entity_registry->destroy(camera_rig_spring_translation_eid);
  271. ctx.entity_registry->destroy(camera_rig_spring_rotation_eid);
  272. ctx.entity_registry->destroy(camera_rig_copy_translation_eid);
  273. ctx.entity_registry->destroy(camera_rig_pivot_eid);
  274. ctx.entity_registry->destroy(camera_rig_focus_eid);
  275. ctx.entity_registry->destroy(camera_rig_focus_ease_to_eid);
  276. ctx.entity_registry->destroy(camera_rig_fov_spring_eid);
  277. }
  278. void nuptial_flight_state::set_camera_rig_zoom(float zoom)
  279. {
  280. }
  281. void nuptial_flight_state::satisfy_camera_rig_constraints()
  282. {
  283. }
  284. void nuptial_flight_state::setup_controls()
  285. {
  286. }
  287. void nuptial_flight_state::enable_controls()
  288. {
  289. }
  290. void nuptial_flight_state::disable_controls()
  291. {
  292. }
  293. void nuptial_flight_state::select_entity(entity::id entity_id)
  294. {
  295. if (entity_id != selected_eid)
  296. {
  297. if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<picking_component>(selected_eid))
  298. {
  299. // Unset selected bit on picking flags of previously selected entity
  300. ctx.entity_registry->patch<picking_component>
  301. (
  302. selected_eid,
  303. [&](auto& component)
  304. {
  305. component.flags &= ~selected_picking_flag;
  306. }
  307. );
  308. }
  309. selected_eid = entity_id;
  310. if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<picking_component>(selected_eid))
  311. {
  312. // Set selected bit on picking flags of current selected entity
  313. ctx.entity_registry->patch<picking_component>
  314. (
  315. selected_eid,
  316. [&](auto& component)
  317. {
  318. component.flags |= selected_picking_flag;
  319. }
  320. );
  321. }
  322. // Update camera rig focus ease to target
  323. ctx.entity_registry->patch<ease_to_constraint>
  324. (
  325. camera_rig_focus_ease_to_eid,
  326. [&](auto& component)
  327. {
  328. component.target = selected_eid;
  329. component.t = 0.0f;
  330. const transform_component* transform = ctx.entity_registry->try_get<transform_component>(camera_rig_focus_eid);
  331. if (transform)
  332. component.start = transform->world.translation;
  333. }
  334. );
  335. // Update selection text
  336. if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<::ant_caste_component>(selected_eid))
  337. {
  338. const auto& caste = ctx.entity_registry->get<::ant_caste_component>(selected_eid);
  339. if (ctx.entity_registry->all_of<::name_component>(selected_eid))
  340. {
  341. const auto& name = ctx.entity_registry->get<::name_component>(selected_eid).name;
  342. std::string format_string;
  343. switch (caste.type)
  344. {
  345. case ::ant_caste_type::queen:
  346. format_string = ::get_string(ctx, "named_queen_label_format");
  347. break;
  348. case ::ant_caste_type::worker:
  349. format_string = ::get_string(ctx, "named_worker_label_format");
  350. break;
  351. case ::ant_caste_type::soldier:
  352. format_string = ::get_string(ctx, "named_soldier_label_format");
  353. break;
  354. case ::ant_caste_type::male:
  355. format_string = ::get_string(ctx, "named_male_label_format");
  356. break;
  357. default:
  358. //std::unreachable();
  359. break;
  360. }
  361. selection_text.set_content(std::vformat(format_string, std::make_format_args(name)));
  362. }
  363. else
  364. {
  365. switch (caste.type)
  366. {
  367. case ::ant_caste_type::queen:
  368. selection_text.set_content(get_string(ctx, "queen_caste_name"));
  369. break;
  370. case ::ant_caste_type::worker:
  371. selection_text.set_content(get_string(ctx, "worker_caste_name"));
  372. break;
  373. case ::ant_caste_type::soldier:
  374. selection_text.set_content(get_string(ctx, "soldier_caste_name"));
  375. break;
  376. case ::ant_caste_type::male:
  377. selection_text.set_content(get_string(ctx, "male_caste_name"));
  378. break;
  379. default:
  380. //std::unreachable();
  381. break;
  382. }
  383. }
  384. const auto& viewport_size = ctx.window->get_viewport_size();
  385. const auto& text_aabb = selection_text.get_bounds();
  386. float text_w = text_aabb.max.x() - text_aabb.min.x();
  387. float text_h = text_aabb.max.y() - text_aabb.min.y();
  388. selection_text.set_translation({std::round(viewport_size.x() * 0.5f - text_w * 0.5f), std::round(ctx.menu_font.get_font_metrics().size), 0.0f});
  389. }
  390. }
  391. }
  392. void nuptial_flight_state::select_nearest_entity(const math::fvec3& direction)
  393. {
  394. if (!ctx.entity_registry->valid(selected_eid))
  395. return;
  396. const transform_component* selected_eid_transform = ctx.entity_registry->try_get<transform_component>(selected_eid);
  397. if (!selected_eid_transform)
  398. return;
  399. // Construct picking plane
  400. const math::fvec3 picking_normal = math::normalize(ctx.surface_camera->get_rotation() * direction);
  401. const math::fvec3 picking_origin = selected_eid_transform->world.translation;
  402. // Pick entity
  403. entity::id picked_eid = ctx.collision_system->pick_nearest(picking_origin, picking_normal, ~selected_picking_flag);
  404. if (picked_eid != entt::null)
  405. {
  406. select_entity(picked_eid);
  407. }
  408. }