Antkeeper  0.0.1
world.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 
20 #include "game/world.hpp"
21 #include <engine/color/color.hpp>
22 #include <engine/config.hpp>
23 #include <engine/debug/log.hpp>
43 #include <engine/math/angles.hpp>
53 #include <engine/render/model.hpp>
56 #include <engine/utility/json.hpp>
59 #include <engine/scene/text.hpp>
60 #include <algorithm>
61 #include <execution>
62 #include <fstream>
65 
66 namespace world {
67 
69 static void load_ephemeris(::game& ctx);
70 
72 static void create_stars(::game& ctx);
73 
75 static void create_sun(::game& ctx);
76 
78 static void create_earth_moon_system(::game& ctx);
79 
81 static void create_earth(::game& ctx);
82 
84 static void create_moon(::game& ctx);
85 
86 void cosmogenesis(::game& ctx)
87 {
88  debug::log_trace("Generating cosmos...");
89 
90  load_ephemeris(ctx);
91  create_stars(ctx);
92  create_sun(ctx);
93  create_earth_moon_system(ctx);
94 
95  debug::log_trace("Generated cosmos");
96 }
97 
98 void create_observer(::game& ctx)
99 {
100  debug::log_trace("Creating observer...");
101 
102  {
103  // Create observer entity
104  entity::id observer_eid = ctx.entity_registry->create();
105  ctx.entities["observer"] = observer_eid;
106 
107  // Construct observer component
108  ::observer_component observer;
109 
110  // Set observer reference body
111  if (auto it = ctx.entities.find("earth"); it != ctx.entities.end())
112  observer.reference_body_eid = it->second;
113  else
114  observer.reference_body_eid = entt::null;
115 
116  // Set observer location
117  observer.elevation = 0.0;
118  observer.latitude = 0.0;
119  observer.longitude = 0.0;
120 
121  // Assign observer component to observer entity
122  ctx.entity_registry->emplace<::observer_component>(observer_eid, observer);
123 
124  // Set atmosphere system active atmosphere
125  ctx.atmosphere_system->set_active_atmosphere(observer.reference_body_eid);
126 
127  // Set astronomy system observer
128  ctx.astronomy_system->set_observer(observer_eid);
129  }
130 
131  debug::log_trace("Created observer");
132 }
133 
134 void set_location(::game& ctx, double elevation, double latitude, double longitude)
135 {
136  if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
137  {
138  entity::id observer_eid = it->second;
139 
140  if (ctx.entity_registry->valid(observer_eid) && ctx.entity_registry->all_of<::observer_component>(observer_eid))
141  {
142  // Update observer location
144  (
145  observer_eid,
146  [&](auto& component)
147  {
148  component.elevation = elevation;
149  component.latitude = latitude;
150  component.longitude = longitude;
151  }
152  );
153  }
154  }
155 }
156 
157 void set_time(::game& ctx, double t)
158 {
159  try
160  {
161  ctx.astronomy_system->set_time(t);
162  ctx.orbit_system->set_time(t);
163 
164  // debug::log_info("Set time to UT1 {}", t);
165  }
166  catch (const std::exception& e)
167  {
168  debug::log_error("Failed to set time to UT1 {}: {}", t, e.what());
169  }
170 }
171 
172 void set_time(::game& ctx, int year, int month, int day, int hour, int minute, double second)
173 {
174  double longitude = 0.0;
175 
176  // Get longitude of observer
177  if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
178  {
179  entity::id observer_eid = it->second;
180  if (ctx.entity_registry->valid(observer_eid))
181  {
182  const auto observer = ctx.entity_registry->try_get<::observer_component>(observer_eid);
183  if (observer)
184  longitude = observer->longitude;
185  }
186  }
187 
188  // Calculate UTC offset at longitude
189  const double utc_offset = physics::time::utc::offset<double>(longitude);
190 
191  // Convert time from Gregorian to UT1
192  const double t = physics::time::gregorian::to_ut1<double>(year, month, day, hour, minute, second, utc_offset);
193 
194  set_time(ctx, t);
195 }
196 
197 void set_time_scale(::game& ctx, double scale)
198 {
199  // Convert time scale from seconds to days
200  const double astronomical_scale = scale / physics::time::seconds_per_day<double>;
201 
202  ctx.orbit_system->set_time_scale(astronomical_scale);
203  ctx.astronomy_system->set_time_scale(astronomical_scale);
204 }
205 
206 void load_ephemeris(::game& ctx)
207 {
208  ctx.orbit_system->set_ephemeris(ctx.resource_manager->load<physics::orbit::ephemeris<double>>("de421.eph"));
209 }
210 
211 void create_stars(::game& ctx)
212 {
213  debug::log_trace("Generating fixed stars...");
214 
215  // Load star catalog
216  auto star_catalog = ctx.resource_manager->load<i18n::string_table>("hipparcos-7.tsv");
217 
218  // Allocate star catalog vertex data
219  std::size_t star_count = 0;
220  if (star_catalog->rows.size() > 0)
221  star_count = star_catalog->rows.size() - 1;
222  constexpr std::size_t star_vertex_stride = 7 * sizeof(float);
223  std::vector<float> star_vertex_data(star_count * star_vertex_stride / sizeof(float));
224  float* star_vertex = star_vertex_data.data();
225 
226  // Init starlight illuminance
227  math::dvec3 starlight_illuminance = {0, 0, 0};
228 
229  // Build star catalog vertex data
230  for (std::size_t i = 1; i < star_catalog->rows.size(); ++i)
231  {
232  const auto& row = star_catalog->rows[i];
233 
234  // Parse star catalog item
235  float ra = 0.0;
236  float dec = 0.0;
237  float vmag = 0.0;
238  float bv = 0.0;
239  try
240  {
241  ra = std::stof(row[1]);
242  dec = std::stof(row[2]);
243  vmag = std::stof(row[3]);
244  bv = std::stof(row[4]);
245  }
246  catch (const std::exception&)
247  {
248  debug::log_warning("Invalid star catalog item on row {}", i);
249  continue;
250  }
251 
252  // Convert right ascension and declination from degrees to radians
254  dec = math::wrap_radians(math::radians(dec));
255 
256  // Convert ICRF coordinates from spherical to Cartesian
258 
259  // Convert color index to color temperature
260  float cct = color::bv_to_cct(bv);
261 
262  // Calculate XYZ color from color temperature
263  math::fvec3 color_xyz = color::cct_to_xyz(cct);
264 
265  // Transform XYZ color to RGB
266  math::fvec3 color_rgb = config::scene_linear_color_space<float>.from_xyz * color_xyz;
267 
268  // Convert apparent magnitude to brightness factor relative to a 0th magnitude star
269  float brightness = physics::light::vmag::to_brightness(vmag);
270 
271  // Build vertex
272  *(star_vertex++) = position.x();
273  *(star_vertex++) = position.y();
274  *(star_vertex++) = position.z();
275  *(star_vertex++) = color_rgb.x();
276  *(star_vertex++) = color_rgb.y();
277  *(star_vertex++) = color_rgb.z();
278  *(star_vertex++) = brightness;
279 
280  // Calculate spectral illuminance
281  math::dvec3 illuminance = math::dvec3(color_rgb * physics::light::vmag::to_illuminance(vmag));
282 
283  // Add spectral illuminance to total starlight illuminance
284  starlight_illuminance += illuminance;
285  }
286 
287  // Allocate stars model
288  std::shared_ptr<render::model> stars_model = std::make_shared<render::model>();
289 
290  // Construct stars VAO
291  constexpr gl::vertex_input_attribute star_vertex_attributes[] =
292  {
293  {
295  0,
297  0
298  },
299  {
301  0,
303  3 * sizeof(float)
304  }
305  };
306  auto& vao = stars_model->get_vertex_array();
307  vao = std::make_unique<gl::vertex_array>(star_vertex_attributes);
308 
309  // Construct stars VBO
310  auto& vbo = stars_model->get_vertex_buffer();
311  vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, std::as_bytes(std::span{star_vertex_data}));
312  stars_model->set_vertex_offset(0);
313  stars_model->set_vertex_stride(star_vertex_stride);
314 
315  // Construct star model group
316  stars_model->get_groups().resize(1);
317  render::model_group& stars_model_group = stars_model->get_groups().front();
318  stars_model_group.id = "stars";
319  stars_model_group.material = ctx.resource_manager->load<render::material>("fixed-star.mtl");
321  stars_model_group.first_vertex = 0;
322  stars_model_group.vertex_count = static_cast<std::uint32_t>(star_count);
323 
324  // Pass stars model to sky pass
325  ctx.sky_pass->set_stars_model(stars_model);
326 
327  // Pass starlight illuminance to astronomy system
328  ctx.astronomy_system->set_starlight_illuminance(starlight_illuminance);
329 
330  debug::log_trace("Generated fixed stars");
331 }
332 
333 void create_sun(::game& ctx)
334 {
335  debug::log_trace("Generating Sun...");
336 
337  {
338  // Create sun entity
339  auto sun_archetype = ctx.resource_manager->load<entity::archetype>("sun.ent");
340  entity::id sun_eid = sun_archetype->create(*ctx.entity_registry);
341  ctx.entities["sun"] = sun_eid;
342 
343  // Create sun directional light scene object
344  ctx.sun_light = std::make_unique<scene::directional_light>();
345  ctx.sun_light->set_shadow_caster(true);
346  ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer);
347  ctx.sun_light->set_shadow_bias(0.005f);
348  ctx.sun_light->set_shadow_max_distance(20.0f);
349  ctx.sun_light->set_shadow_fade_range(5.0f);
350  ctx.sun_light->set_shadow_cascade_count(4);
351  ctx.sun_light->set_shadow_cascade_distribution(0.8f);
352 
353  // Add sun light scene objects to surface scene
354  ctx.surface_scene->add_object(*ctx.sun_light);
355 
356  // Pass direct sun light scene object to shadow map pass and astronomy system
357  ctx.astronomy_system->set_sun_light(ctx.sun_light.get());
358  }
359 
360  debug::log_trace("Generated Sun");
361 }
362 
363 void create_earth_moon_system(::game& ctx)
364 {
365  debug::log_trace("Generating Earth-Moon system...");
366 
367  {
368  // Create Earth-Moon barycenter entity
369  auto em_bary_archetype = ctx.resource_manager->load<entity::archetype>("em-bary.ent");
370  entity::id em_bary_eid = em_bary_archetype->create(*ctx.entity_registry);
371  ctx.entities["em_bary"] = em_bary_eid;
372 
373  // Create Earth
374  create_earth(ctx);
375 
376  // Create Moon
377  create_moon(ctx);
378  }
379 
380  debug::log_trace("Generated Earth-Moon system");
381 }
382 
383 void create_earth(::game& ctx)
384 {
385  debug::log_trace("Generating Earth...");
386 
387  {
388  // Create earth entity
389  auto earth_archetype = ctx.resource_manager->load<entity::archetype>("earth.ent");
390  entity::id earth_eid = earth_archetype->create(*ctx.entity_registry);
391  ctx.entities["earth"] = earth_eid;
392 
393  // Assign orbital parent
394  ctx.entity_registry->get<::orbit_component>(earth_eid).parent = ctx.entities["em_bary"];
395  }
396 
397  debug::log_trace("Generated Earth");
398 }
399 
400 void create_moon(::game& ctx)
401 {
402  debug::log_trace("Generating Moon...");
403 
404  {
405  // Create lunar entity
406  auto moon_archetype = ctx.resource_manager->load<entity::archetype>("moon.ent");
407  entity::id moon_eid = moon_archetype->create(*ctx.entity_registry);
408  ctx.entities["moon"] = moon_eid;
409 
410  // Assign orbital parent
411  ctx.entity_registry->get<::orbit_component>(moon_eid).parent = ctx.entities["em_bary"];
412 
413  // Pass moon model to sky pass
414  ctx.sky_pass->set_moon_model(ctx.resource_manager->load<render::model>("moon.mdl"));
415 
416  // Create moon directional light scene object
417  ctx.moon_light = std::make_unique<scene::directional_light>();
418 
419  // Add moon light scene objects to surface scene
420  ctx.surface_scene->add_object(*ctx.moon_light);
421 
422  // Pass moon light scene object to astronomy system
423  ctx.astronomy_system->set_moon_light(ctx.moon_light.get());
424  }
425 
426  debug::log_trace("Generated Moon");
427 }
428 
430 {
431  debug::log_trace("Entering ecoregion {}...", ecoregion.name);
432  {
433  // Set active ecoregion
434  //ctx.active_ecoregion = &ecoregion;
435 
436  // Set location
438 
439  // Setup sky
440  ctx.sky_pass->set_sky_model(ctx.resource_manager->load<render::model>("celestial-hemisphere.mdl"));
441  ctx.sky_pass->set_ground_albedo(ecoregion.terrain_albedo);
442 
443  // Setup terrain
444  // ctx.terrain_system->set_patch_material(ecoregion.terrain_material);
445  // ctx.terrain_system->set_elevation_function
446  // (
447  // [](float x, float z) -> float
448  // {
449  // const math::fvec2 position = math::fvec2{x, z};
450 
451  // const std::size_t octaves = 3;
452  // const float lacunarity = 1.5f;
453  // const float gain = 0.5f;
454 
455  // const float fbm = math::noise::fbm
456  // (
457  // position * 0.005f,
458  // octaves,
459  // lacunarity,
460  // gain
461  // );
462 
463  // float y = fbm * 4.0f;
464 
465  // return y;
466  // }
467  // );
468  }
469 
470  debug::log_trace("Entered ecoregion {}", ecoregion.name);
471 }
472 
473 void switch_scene(::game& ctx)
474 {
475  ctx.fade_transition_color->set({0, 0, 0});
476  ctx.fade_transition->transition(1.0f, false, ease<float>::out_cubic, false, [](){});
477 }
478 
479 } // namespace world
Definition: game.hpp:121
std::shared_ptr< gl::framebuffer > shadow_map_framebuffer
Definition: game.hpp:314
std::unique_ptr< scene::collection > surface_scene
Definition: game.hpp:356
std::unique_ptr< screen_transition > fade_transition
Definition: game.hpp:371
std::unique_ptr< scene::directional_light > sun_light
Definition: game.hpp:358
std::unique_ptr< scene::directional_light > moon_light
Definition: game.hpp:359
std::unique_ptr<::astronomy_system > astronomy_system
Definition: game.hpp:416
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< render::matvar_fvec3 > fade_transition_color
Definition: game.hpp:372
std::unique_ptr<::atmosphere_system > atmosphere_system
Definition: game.hpp:415
std::unique_ptr< entity::registry > entity_registry
Definition: game.hpp:392
std::unique_ptr<::orbit_system > orbit_system
Definition: game.hpp:417
std::unordered_map< hash::fnv1a32_t, entity::id > entities
Definition: game.hpp:393
A material is associated with exactly one shader program and contains a set of material properties wh...
Definition: material.hpp:37
T bv_to_cct(T bv) noexcept
Approximates the temperature of a star, given its B-V index.
Definition: index.hpp:37
math::vec3< T > cct_to_xyz(T t)
Calculates CIE XYZ colorspace chromaticity coordinates given a correlated color temperature using Kry...
Definition: cct.hpp:70
log_message< log_message_severity::warning, Args... > log_warning
Formats and logs a warning message.
Definition: log.hpp:130
log_message< log_message_severity::trace, Args... > log_trace
Formats and logs a trace message.
Definition: log.hpp:88
log_message< log_message_severity::error, Args... > log_error
Formats and logs an error message.
Definition: log.hpp:144
entt::entity id
Entity ID type.
Definition: id.hpp:28
@ r32g32b32a32_sfloat
@ static_draw
Data will be modified once, by the application, and used many times, for drawing commands.
@ point_list
Separate point primitives.
@ row
Faces are stored consecutively in a single row.
dvec< 3 > dvec3
n-dimensional vector of double-precision floating-point numbers.
Definition: vector.hpp:438
constexpr T radians(T degrees) noexcept
Converts an angle given in degrees to radians.
Definition: angles.hpp:48
constexpr mat4< T > scale(const vec3< T > &v)
Constructs a scale matrix.
constexpr T wrap_radians(T radians)
Wraps an angle to [-pi, pi].
Definition: angles.hpp:72
T to_brightness(T mv)
Converts apparent magnitude to a brightness factor relative to a 0th magnitude star.
Definition: vmag.hpp:40
T to_illuminance(T mv)
Converts apparent magnitude to illuminance.
Definition: vmag.hpp:56
math::vec3< T > cartesian(const math::vec3< T > &v)
Converts BCI coordinates from spherical to Cartesian.
Definition: frame.hpp:170
World creation and manipulation functions.
Definition: world.cpp:66
void cosmogenesis(::game &ctx)
Creates the cosmos.
Definition: world.cpp:86
void create_observer(::game &ctx)
Creates the observer.
Definition: world.cpp:98
void set_location(::game &ctx, double elevation, double latitude, double longitude)
Sets the location of the observer.
Definition: world.cpp:134
void enter_ecoregion(::game &ctx, const ecoregion &ecoregion)
Enters a ecoregion.
Definition: world.cpp:429
void switch_scene(::game &ctx)
Definition: world.cpp:473
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
Container for templated easing functions.
Definition: ease.hpp:71
std::string name
Ecoregion name.
Definition: ecoregion.hpp:36
float latitude
Latitude, in radians.
Definition: ecoregion.hpp:42
math::fvec3 terrain_albedo
Terrain albedo.
Definition: ecoregion.hpp:51
float elevation
Elevation, in meters.
Definition: ecoregion.hpp:39
float longitude
Longitude, in radians.
Definition: ecoregion.hpp:45
Entity type template.
Definition: archetype.hpp:34
entity::id create(entity::registry &registry) const
Creates an instance of this archetype.
Definition: archetype.cpp:25
Table of strings.
std::vector< std::vector< std::string > > rows
Rows of column strings.
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
constexpr element_type & z() noexcept
Returns a reference to the third element.
Definition: vector.hpp:196
double latitude
Latitude of the observer, in radians.
entity::id reference_body_eid
Entity ID of a celestial body to which the observer position is relative.
double elevation
Elevation of the observer, in radians.
double longitude
Longitude of the observer, in radians.
Table of orbital trajectories.
Definition: ephemeris.hpp:36
Part of a model which is associated with exactly one material.
Definition: model.hpp:41
std::shared_ptr< render::material > material
Definition: model.hpp:46
gl::primitive_topology primitive_topology
Definition: model.hpp:43
std::uint32_t vertex_count
Definition: model.hpp:45
std::uint32_t first_vertex
Definition: model.hpp:44
hash::fnv1a32_t id
Definition: model.hpp:42