Antkeeper  0.0.1
nuptial-flight-state.cpp
Go to the documentation of this file.
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 
23 #include "game/ant/ant-swarm.hpp"
50 #include "game/controls.hpp"
55 #include "game/world.hpp"
56 #include "game/strings.hpp"
58 #include <engine/config.hpp>
61 #include <engine/color/color.hpp>
62 #include <engine/input/mouse.hpp>
64 #include <random>
65 
66 using namespace hash::literals;
67 
69  game_state(ctx)
70 {
71  debug::log_trace("Entering nuptial flight state...");
72 
73  // Init selected picking flag
74  selected_picking_flag = std::uint32_t{1} << (sizeof(std::uint32_t) * 8 - 1);
75  selected_eid = entt::null;
76 
77  // Create world if not yet created
78  if (ctx.entities.find("earth") == ctx.entities.end())
79  {
80  // Create cosmos
82 
83  // Create observer
85  }
86  ::world::enter_ecoregion(ctx, *ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco"));
87 
88  // Set world time
89  ::world::set_time(ctx, 2022, 6, 21, 12, 0, 0.0);
90 
91  // Set world time scale
93 
94  // Setup and enable sky and ground passes
95  ctx.sky_pass->set_enabled(true);
96 
97  // Create mating swarm
98  swarm_eid = create_ant_swarm(ctx);
99 
100  // Load name pool
101  name_pool = ctx.resource_manager->load<text_file>("name-pool-en.txt");
102 
103  // Assign random ant names
104  std::uniform_int_distribution<> name_pool_distribution(0, static_cast<int>(name_pool->lines.size() - 1));
106  (
107  [&](entity::id entity_id, const auto& caste)
108  {
109  ctx.entity_registry->emplace_or_replace<name_component>
110  (
111  entity_id,
112  name_pool->lines[name_pool_distribution(ctx.rng)]
113  );
114  }
115  );
116 
117  // Set camera exposure
118  const float ev100_sunny16 = physics::light::ev::from_settings(16.0f, 1.0f / 100.0f, 100.0f);
119  ctx.surface_camera->set_exposure_value(ev100_sunny16);
120 
121  const auto& viewport_size = ctx.window->get_viewport_size();
122  const float aspect_ratio = static_cast<float>(viewport_size[0]) / static_cast<float>(viewport_size[1]);
123 
124  // Init camera rig params
125  camera_rig_near_distance = 1.0f;
126  camera_rig_far_distance = 150.0f;
127  camera_rig_near_fov = math::vertical_fov(math::radians(100.0f), aspect_ratio);
128  camera_rig_far_fov = math::vertical_fov(math::radians(60.0f), aspect_ratio);
129  camera_rig_zoom_speed = 4.0f;
130  camera_rig_translation_spring_angular_frequency = physics::s_to_rads(0.125f);
131  camera_rig_rotation_spring_angular_frequency = physics::s_to_rads(0.125f);
132  camera_rig_fov_spring_angular_frequency = physics::s_to_rads(0.125f);
133  camera_rig_focus_ease_to_duration = 1.0f;
134 
135  // Create camera rig
136  create_camera_rig();
137 
138  // Construct selection text
139  selection_text.set_material(ctx.menu_font_material);
140  selection_text.set_color({1.0f, 1.0f, 1.0f, 1.0f});
141  selection_text.set_font(&ctx.menu_font);
142  const auto& text_aabb = selection_text.get_bounds();
143  float text_w = text_aabb.max.x() - text_aabb.min.x();
144  float text_h = text_aabb.max.y() - text_aabb.min.y();
145  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});
146 
147  // Add text to UI
148  ctx.ui_scene->add_object(selection_text);
149 
150  // Select random alate
151  entity::id random_alate_eid;
153  (
154  [&](entity::id entity_id, auto& transform, auto& steering)
155  {
156  random_alate_eid = entity_id;
157  }
158  );
159  select_entity(random_alate_eid);
160 
161  // Satisfy camera rig constraints
162  satisfy_camera_rig_constraints();
163 
164  // Setup controls
165  setup_controls();
166 
167  // Queue enable controls
168  ctx.function_queue.push
169  (
170  [&ctx]()
171  {
173  }
174  );
175 
176  // Queue fade in
177  ctx.fade_transition_color->set({0, 0, 0});
178  ctx.function_queue.push(std::bind(&screen_transition::transition, ctx.fade_transition.get(), 1.0f, true, ease<float>::out_sine, true, nullptr));
179 
180  // Refresh frame scheduler
182 
183  debug::log_trace("Entered nuptial flight state");
184 }
185 
187 {
188  debug::log_trace("Exiting nuptial flight state...");
189 
190  // Disable game controls
192 
193  // Remove text from UI
194  ctx.ui_scene->remove_object(selection_text);
195 
196  // Deselect selected entity
197  select_entity(entt::null);
198 
199 
200  destroy_camera_rig();
201  destroy_ant_swarm(ctx, swarm_eid);
202 
203  debug::log_trace("Exited nuptial flight state");
204 }
205 
206 void nuptial_flight_state::create_camera_rig()
207 {
208  // Construct camera rig focus ease to constraint
209  ease_to_constraint camera_rig_focus_ease_to;
210  camera_rig_focus_ease_to.target = selected_eid;
211  camera_rig_focus_ease_to.start = {0, 0, 0};
212  camera_rig_focus_ease_to.duration = camera_rig_focus_ease_to_duration;
213  camera_rig_focus_ease_to.t = camera_rig_focus_ease_to.duration;
214  camera_rig_focus_ease_to.function = &ease<math::fvec3, float>::out_expo;
215  constraint_stack_node_component camera_rig_focus_ease_to_node;
216  camera_rig_focus_ease_to_node.active = true;
217  camera_rig_focus_ease_to_node.weight = 1.0f;
218  camera_rig_focus_ease_to_node.next = entt::null;
219  camera_rig_focus_ease_to_eid = ctx.entity_registry->create();
220  ctx.entity_registry->emplace<ease_to_constraint>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to);
221  ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_focus_ease_to_eid, camera_rig_focus_ease_to_node);
222 
223  // Construct camera rig focus constraint stack
224  constraint_stack_component camera_rig_focus_constraint_stack;
225  camera_rig_focus_constraint_stack.priority = 1;
226  camera_rig_focus_constraint_stack.head = camera_rig_focus_ease_to_eid;
227 
228  // Construct camera rig focus transform component
229  transform_component camera_rig_focus_transform;
230  camera_rig_focus_transform.local = math::transform<float>::identity();
231  camera_rig_focus_transform.world = camera_rig_focus_transform.local;
232 
233  // Construct camera rig focus entity
234  camera_rig_focus_eid = ctx.entity_registry->create();
235  ctx.entity_registry->emplace<transform_component>(camera_rig_focus_eid, camera_rig_focus_transform);
236  ctx.entity_registry->emplace<constraint_stack_component>(camera_rig_focus_eid, camera_rig_focus_constraint_stack);
237 
238  // Construct camera rig pivot constraint
239  pivot_constraint camera_rig_pivot;
240  camera_rig_pivot.target = camera_rig_focus_eid;
241  camera_rig_pivot.offset = {0, 0, 0};
242  constraint_stack_node_component camera_rig_pivot_node;
243  camera_rig_pivot_node.active = true;
244  camera_rig_pivot_node.weight = 1.0f;
245  camera_rig_pivot_node.next = entt::null;
246  camera_rig_pivot_eid = ctx.entity_registry->create();
247  ctx.entity_registry->emplace<pivot_constraint>(camera_rig_pivot_eid, camera_rig_pivot);
248  ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_pivot_eid, camera_rig_pivot_node);
249 
250  // Construct camera rig copy translation constraint
251  copy_translation_constraint camera_rig_copy_translation;
252  camera_rig_copy_translation.target = camera_rig_focus_eid;
253  camera_rig_copy_translation.copy_x = true;
254  camera_rig_copy_translation.copy_y = true;
255  camera_rig_copy_translation.copy_z = true;
256  camera_rig_copy_translation.invert_x = false;
257  camera_rig_copy_translation.invert_y = false;
258  camera_rig_copy_translation.invert_z = false;
259  camera_rig_copy_translation.offset = true;
260  constraint_stack_node_component camera_rig_copy_translation_node;
261  camera_rig_copy_translation_node.active = true;
262  camera_rig_copy_translation_node.weight = 1.0f;
263  camera_rig_copy_translation_node.next = camera_rig_pivot_eid;
264  camera_rig_copy_translation_eid = ctx.entity_registry->create();
265  ctx.entity_registry->emplace<copy_translation_constraint>(camera_rig_copy_translation_eid, camera_rig_copy_translation);
266  ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_copy_translation_eid, camera_rig_copy_translation_node);
267 
268  // Construct camera rig spring rotation constraint
269  spring_rotation_constraint camera_rig_spring_rotation;
270  camera_rig_spring_rotation.spring.set_angular_frequency(camera_rig_rotation_spring_angular_frequency);
271  constraint_stack_node_component camera_rig_spring_rotation_node;
272  camera_rig_spring_rotation_node.active = true;
273  camera_rig_spring_rotation_node.weight = 1.0f;
274  camera_rig_spring_rotation_node.next = camera_rig_copy_translation_eid;
275  camera_rig_spring_rotation_eid = ctx.entity_registry->create();
276  ctx.entity_registry->emplace<spring_rotation_constraint>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation);
277  ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_spring_rotation_eid, camera_rig_spring_rotation_node);
278 
279  // Construct camera rig spring translation constraint
280  spring_translation_constraint camera_rig_spring_translation;
281  camera_rig_spring_translation.spring.set_angular_frequency(camera_rig_translation_spring_angular_frequency);
282  constraint_stack_node_component camera_rig_spring_translation_node;
283  camera_rig_spring_translation_node.active = true;
284  camera_rig_spring_translation_node.weight = 1.0f;
285  camera_rig_spring_translation_node.next = camera_rig_spring_rotation_eid;
286  camera_rig_spring_translation_eid = ctx.entity_registry->create();
287  ctx.entity_registry->emplace<spring_translation_constraint>(camera_rig_spring_translation_eid, camera_rig_spring_translation);
288  ctx.entity_registry->emplace<constraint_stack_node_component>(camera_rig_spring_translation_eid, camera_rig_spring_translation_node);
289 
290  // Construct camera rig constraint stack
291  constraint_stack_component camera_rig_constraint_stack;
292  camera_rig_constraint_stack.priority = 2;
293  camera_rig_constraint_stack.head = camera_rig_spring_translation_eid;
294 
295  // Construct camera rig transform component
296  transform_component camera_rig_transform;
297  camera_rig_transform.local = math::transform<float>::identity();
298  camera_rig_transform.world = camera_rig_transform.local;
299 
300  // Construct camera rig camera component
301  scene_component camera_rig_camera;
302  camera_rig_camera.object = ctx.surface_camera;
303 
304  // Construct camera rig entity
305  camera_rig_eid = ctx.entity_registry->create();
306  ctx.entity_registry->emplace<scene_component>(camera_rig_eid, camera_rig_camera);
307  ctx.entity_registry->emplace<transform_component>(camera_rig_eid, camera_rig_transform);
308  ctx.entity_registry->emplace<constraint_stack_component>(camera_rig_eid, camera_rig_constraint_stack);
309 
310  set_camera_rig_zoom(0.25f);
311 }
312 
313 void nuptial_flight_state::destroy_camera_rig()
314 {
315  ctx.entity_registry->destroy(camera_rig_eid);
316  ctx.entity_registry->destroy(camera_rig_spring_translation_eid);
317  ctx.entity_registry->destroy(camera_rig_spring_rotation_eid);
318  ctx.entity_registry->destroy(camera_rig_copy_translation_eid);
319  ctx.entity_registry->destroy(camera_rig_pivot_eid);
320 
321  ctx.entity_registry->destroy(camera_rig_focus_eid);
322  ctx.entity_registry->destroy(camera_rig_focus_ease_to_eid);
323 
324  ctx.entity_registry->destroy(camera_rig_fov_spring_eid);
325 }
326 
327 void nuptial_flight_state::set_camera_rig_zoom(float zoom)
328 {
329 
330 }
331 
332 void nuptial_flight_state::satisfy_camera_rig_constraints()
333 {
334 
335 }
336 
337 void nuptial_flight_state::setup_controls()
338 {
339 
340 }
341 
342 void nuptial_flight_state::enable_controls()
343 {
344 
345 }
346 
347 void nuptial_flight_state::disable_controls()
348 {
349 
350 }
351 
352 void nuptial_flight_state::select_entity(entity::id entity_id)
353 {
354  if (entity_id != selected_eid)
355  {
356  if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<picking_component>(selected_eid))
357  {
358  // Unset selected bit on picking flags of previously selected entity
360  (
361  selected_eid,
362  [&](auto& component)
363  {
364  component.flags &= ~selected_picking_flag;
365 
366  }
367  );
368  }
369 
370  selected_eid = entity_id;
371 
372  if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<picking_component>(selected_eid))
373  {
374  // Set selected bit on picking flags of current selected entity
376  (
377  selected_eid,
378  [&](auto& component)
379  {
380  component.flags |= selected_picking_flag;
381  }
382  );
383  }
384 
385  // Update camera rig focus ease to target
387  (
388  camera_rig_focus_ease_to_eid,
389  [&](auto& component)
390  {
391  component.target = selected_eid;
392  component.t = 0.0f;
393 
394  const transform_component* transform = ctx.entity_registry->try_get<transform_component>(camera_rig_focus_eid);
395  if (transform)
396  component.start = transform->world.translation;
397  }
398  );
399 
400  // Update selection text
401  if (ctx.entity_registry->valid(selected_eid) && ctx.entity_registry->all_of<::ant_caste_component>(selected_eid))
402  {
403  const auto& caste = ctx.entity_registry->get<::ant_caste_component>(selected_eid);
404 
405  if (ctx.entity_registry->all_of<::name_component>(selected_eid))
406  {
407  const auto& name = ctx.entity_registry->get<::name_component>(selected_eid).name;
408 
409  std::string format_string;
410  switch (caste.type)
411  {
412  case ::ant_caste_type::queen:
413  format_string = ::get_string(ctx, "named_queen_label_format");
414  break;
415 
416  case ::ant_caste_type::worker:
417  format_string = ::get_string(ctx, "named_worker_label_format");
418  break;
419 
420  case ::ant_caste_type::soldier:
421  format_string = ::get_string(ctx, "named_soldier_label_format");
422  break;
423 
424  case ::ant_caste_type::male:
425  format_string = ::get_string(ctx, "named_male_label_format");
426  break;
427 
428  default:
429  //std::unreachable();
430  break;
431  }
432 
433  selection_text.set_content(std::vformat(format_string, std::make_format_args(name)));
434  }
435  else
436  {
437  switch (caste.type)
438  {
439  case ::ant_caste_type::queen:
440  selection_text.set_content(get_string(ctx, "queen_caste_name"));
441  break;
442 
443  case ::ant_caste_type::worker:
444  selection_text.set_content(get_string(ctx, "worker_caste_name"));
445  break;
446 
447  case ::ant_caste_type::soldier:
448  selection_text.set_content(get_string(ctx, "soldier_caste_name"));
449  break;
450 
451  case ::ant_caste_type::male:
452  selection_text.set_content(get_string(ctx, "male_caste_name"));
453  break;
454 
455  default:
456  //std::unreachable();
457  break;
458  }
459  }
460 
461  const auto& viewport_size = ctx.window->get_viewport_size();
462  const auto& text_aabb = selection_text.get_bounds();
463  float text_w = text_aabb.max.x() - text_aabb.min.x();
464  float text_h = text_aabb.max.y() - text_aabb.min.y();
465  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});
466  }
467  }
468 }
469 
470 void nuptial_flight_state::select_nearest_entity(const math::fvec3& direction)
471 {
472  if (!ctx.entity_registry->valid(selected_eid))
473  return;
474 
475  const transform_component* selected_eid_transform = ctx.entity_registry->try_get<transform_component>(selected_eid);
476  if (!selected_eid_transform)
477  return;
478 
479  // Construct picking plane
480  const math::fvec3 picking_normal = math::normalize(ctx.surface_camera->get_rotation() * direction);
481  const math::fvec3 picking_origin = selected_eid_transform->world.translation;
482 
483  // Pick entity
484  entity::id picked_eid = ctx.collision_system->pick_nearest(picking_origin, picking_normal, ~selected_picking_flag);
485  if (picked_eid != entt::null)
486  {
487  select_entity(picked_eid);
488  }
489 }
entity::id create_ant_swarm(::game &ctx)
Definition: ant-swarm.cpp:53
void destroy_ant_swarm(::game &ctx, entity::id swarm_eid)
Definition: ant-swarm.cpp:169
void refresh() noexcept
Resets the accumulated time (at) and frame timer, but not the elapsed fixed-rate update time.
Abstract base class for game states.
Definition: game-state.hpp:29
::game & ctx
Definition: game-state.hpp:44
Definition: game.hpp:121
std::unique_ptr< scene::collection > ui_scene
Definition: game.hpp:333
::frame_scheduler frame_scheduler
Definition: game.hpp:423
std::unique_ptr< screen_transition > fade_transition
Definition: game.hpp:371
std::shared_ptr< scene::camera > surface_camera
Definition: game.hpp:357
type::bitmap_font menu_font
Definition: game.hpp:188
std::unique_ptr<::collision_system > collision_system
Definition: game.hpp:400
std::mt19937 rng
Definition: game.hpp:389
std::unique_ptr< resource_manager > resource_manager
Definition: game.hpp:152
std::unique_ptr< render::sky_pass > sky_pass
Definition: game.hpp:327
std::shared_ptr< app::window > window
Definition: game.hpp:166
std::queue< std::function< void()> > function_queue
Definition: game.hpp:303
std::shared_ptr< render::matvar_fvec3 > fade_transition_color
Definition: game.hpp:372
std::shared_ptr< render::material > menu_font_material
Definition: game.hpp:191
std::unique_ptr< entity::registry > entity_registry
Definition: game.hpp:392
std::unordered_map< hash::fnv1a32_t, entity::id > entities
Definition: game.hpp:393
void set_translation(const vector_type &translation)
Sets the translation of the object.
Definition: object.hpp:85
void set_content(const std::string &content)
Sets the text content.
Definition: text.cpp:116
void set_color(const math::fvec4 &color)
Sets the text color.
Definition: text.cpp:126
const aabb_type & get_bounds() const noexcept override
Returns the bounds of the object.
Definition: text.hpp:116
void set_material(std::shared_ptr< render::material > material)
Sets the text material.
Definition: text.cpp:93
void set_font(const type::bitmap_font *font)
Sets the text font.
Definition: text.cpp:98
void transition(float duration, bool reverse, animation< float >::interpolator_type interpolator, bool hide=true, const std::function< void()> &callback=nullptr)
const font_metrics & get_font_metrics() const
Returns metrics describing the font.
Definition: font.hpp:109
void enable_game_controls(::game &ctx)
Definition: controls.cpp:412
void disable_game_controls(::game &ctx)
Definition: controls.cpp:417
log_message< log_message_severity::trace, Args... > log_trace
Formats and logs a trace message.
Definition: log.hpp:88
entt::entity id
Entity ID type.
Definition: id.hpp:28
User-defined literals for compile-time string hashing.
Definition: fnv1a.hpp:232
T vertical_fov(T h, T r)
Calculates a vertical FoV given a horizontal FoV and aspect ratio.
constexpr vector< T, N > round(const vector< T, N > &x)
Performs a element-wise round operation.
Definition: vector.hpp:1489
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:679
constexpr T radians(T degrees) noexcept
Converts an angle given in degrees to radians.
Definition: angles.hpp:48
T from_settings(T n, T t, T s)
Exposure value from exposure settings.
Definition: exposure.hpp:75
constexpr T s_to_rads(T t) noexcept
Converts oscillation period to angular frequency.
Definition: frequency.hpp:67
void cosmogenesis(::game &ctx)
Creates the cosmos.
Definition: world.cpp:86
void create_observer(::game &ctx)
Creates the observer.
Definition: world.cpp:98
void enter_ecoregion(::game &ctx, const ecoregion &ecoregion)
Enters a ecoregion.
Definition: world.cpp:429
void set_time_scale(::game &ctx, double scale)
Sets rate at which time passes.
Definition: world.cpp:197
void set_time(::game &ctx, double t)
Sets the current time.
Definition: world.cpp:157
std::string get_string(const ::game &ctx, hash::fnv1a32_t key)
Returns a localized string.
Definition: strings.cpp:23
Causes an ordered stack of constraints to be applied to an entity.
int priority
Priority number, with lower priorities evaluated first.
Single node in a constraint stack.
float weight
Controls the amount of influence the constraint has on the final result.
bool active
Enables or disables the constraint.
entity::id next
ID of the entity containing the next constraint in the constraint stack.
Copies the translation of a target entity.
entity::id target
Target entity ID.
Eases toward a target entity.
entity::id target
Target entity ID.
math::fvec3 start
Start position.
float duration
Total duration of the ease.
float t
Elapsed time since ease began.
math::fvec3(* function)(const math::fvec3 &, const math::fvec3 &, float)
Pointer to the interpolation function.
Container for templated easing functions.
Definition: ease.hpp:71
vector_type max
Maximum extent of the hyperrectangle.
static constexpr transform identity() noexcept
Returns an identity transform.
Definition: transform.hpp:107
vector_type translation
Translation vector.
Definition: transform.hpp:50
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
Supplies a human-readable name.
Pivots around a target entity.
entity::id target
Target entity ID.
std::shared_ptr< scene::object_base > object
physics::numeric_spring< math::fvec3, float > spring
Yaw, pitch, and roll angle spring.
physics::numeric_spring< math::fvec3, float > spring
Translation spring.
Virtual text file.
Definition: text-file.hpp:30
math::transform< float > world
math::transform< float > local
float size
Vertical size of the font.