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

479 lines
14 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/world.hpp"
  20. #include <engine/color/color.hpp>
  21. #include <engine/config.hpp>
  22. #include <engine/debug/log.hpp>
  23. #include <engine/entity/archetype.hpp>
  24. #include "game/commands/commands.hpp"
  25. #include "game/components/atmosphere-component.hpp"
  26. #include "game/components/blackbody-component.hpp"
  27. #include "game/components/celestial-body-component.hpp"
  28. #include "game/components/observer-component.hpp"
  29. #include "game/components/orbit-component.hpp"
  30. #include "game/components/terrain-component.hpp"
  31. #include "game/components/transform-component.hpp"
  32. #include "game/systems/astronomy-system.hpp"
  33. #include "game/systems/atmosphere-system.hpp"
  34. #include "game/systems/orbit-system.hpp"
  35. #include "game/systems/terrain-system.hpp"
  36. #include <engine/geom/solid-angle.hpp>
  37. #include <engine/gl/vertex-array.hpp>
  38. #include <engine/gl/vertex-buffer.hpp>
  39. #include <engine/i18n/string-table.hpp>
  40. #include <engine/math/hash/hash.hpp>
  41. #include <engine/math/noise/noise.hpp>
  42. #include <engine/math/angles.hpp>
  43. #include <engine/physics/light/photometry.hpp>
  44. #include <engine/physics/light/vmag.hpp>
  45. #include <engine/physics/orbit/ephemeris.hpp>
  46. #include <engine/physics/orbit/orbit.hpp>
  47. #include <engine/physics/time/constants.hpp>
  48. #include <engine/physics/time/gregorian.hpp>
  49. #include <engine/physics/time/utc.hpp>
  50. #include <engine/render/material-flags.hpp>
  51. #include <engine/render/material.hpp>
  52. #include <engine/render/model.hpp>
  53. #include <engine/render/passes/sky-pass.hpp>
  54. #include <engine/render/vertex-attribute-location.hpp>
  55. #include <engine/utility/json.hpp>
  56. #include <engine/resources/resource-manager.hpp>
  57. #include <engine/scene/directional-light.hpp>
  58. #include <engine/scene/text.hpp>
  59. #include <algorithm>
  60. #include <execution>
  61. #include <fstream>
  62. #include <engine/animation/screen-transition.hpp>
  63. #include <engine/animation/ease.hpp>
  64. namespace world {
  65. /// Loads an ephemeris.
  66. static void load_ephemeris(::game& ctx);
  67. /// Creates the fixed stars.
  68. static void create_stars(::game& ctx);
  69. /// Creates the Sun.
  70. static void create_sun(::game& ctx);
  71. /// Creates the Earth-Moon system.
  72. static void create_earth_moon_system(::game& ctx);
  73. /// Creates the Earth.
  74. static void create_earth(::game& ctx);
  75. /// Creates the Moon.
  76. static void create_moon(::game& ctx);
  77. void cosmogenesis(::game& ctx)
  78. {
  79. debug::log_trace("Generating cosmos...");
  80. load_ephemeris(ctx);
  81. create_stars(ctx);
  82. create_sun(ctx);
  83. create_earth_moon_system(ctx);
  84. debug::log_trace("Generated cosmos");
  85. }
  86. void create_observer(::game& ctx)
  87. {
  88. debug::log_trace("Creating observer...");
  89. {
  90. // Create observer entity
  91. entity::id observer_eid = ctx.entity_registry->create();
  92. ctx.entities["observer"] = observer_eid;
  93. // Construct observer component
  94. ::observer_component observer;
  95. // Set observer reference body
  96. if (auto it = ctx.entities.find("earth"); it != ctx.entities.end())
  97. observer.reference_body_eid = it->second;
  98. else
  99. observer.reference_body_eid = entt::null;
  100. // Set observer location
  101. observer.elevation = 0.0;
  102. observer.latitude = 0.0;
  103. observer.longitude = 0.0;
  104. // Assign observer component to observer entity
  105. ctx.entity_registry->emplace<::observer_component>(observer_eid, observer);
  106. // Set atmosphere system active atmosphere
  107. ctx.atmosphere_system->set_active_atmosphere(observer.reference_body_eid);
  108. // Set astronomy system observer
  109. ctx.astronomy_system->set_observer(observer_eid);
  110. }
  111. debug::log_trace("Created observer");
  112. }
  113. void set_location(::game& ctx, double elevation, double latitude, double longitude)
  114. {
  115. if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
  116. {
  117. entity::id observer_eid = it->second;
  118. if (ctx.entity_registry->valid(observer_eid) && ctx.entity_registry->all_of<::observer_component>(observer_eid))
  119. {
  120. // Update observer location
  121. ctx.entity_registry->patch<::observer_component>
  122. (
  123. observer_eid,
  124. [&](auto& component)
  125. {
  126. component.elevation = elevation;
  127. component.latitude = latitude;
  128. component.longitude = longitude;
  129. }
  130. );
  131. }
  132. }
  133. }
  134. void set_time(::game& ctx, double t)
  135. {
  136. try
  137. {
  138. ctx.astronomy_system->set_time(t);
  139. ctx.orbit_system->set_time(t);
  140. // debug::log_info("Set time to UT1 {}", t);
  141. }
  142. catch (const std::exception& e)
  143. {
  144. debug::log_error("Failed to set time to UT1 {}: {}", t, e.what());
  145. }
  146. }
  147. void set_time(::game& ctx, int year, int month, int day, int hour, int minute, double second)
  148. {
  149. double longitude = 0.0;
  150. // Get longitude of observer
  151. if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
  152. {
  153. entity::id observer_eid = it->second;
  154. if (ctx.entity_registry->valid(observer_eid))
  155. {
  156. const auto observer = ctx.entity_registry->try_get<::observer_component>(observer_eid);
  157. if (observer)
  158. longitude = observer->longitude;
  159. }
  160. }
  161. // Calculate UTC offset at longitude
  162. const double utc_offset = physics::time::utc::offset<double>(longitude);
  163. // Convert time from Gregorian to UT1
  164. const double t = physics::time::gregorian::to_ut1<double>(year, month, day, hour, minute, second, utc_offset);
  165. set_time(ctx, t);
  166. }
  167. void set_time_scale(::game& ctx, double scale)
  168. {
  169. // Convert time scale from seconds to days
  170. const double astronomical_scale = scale / physics::time::seconds_per_day<double>;
  171. ctx.orbit_system->set_time_scale(astronomical_scale);
  172. ctx.astronomy_system->set_time_scale(astronomical_scale);
  173. }
  174. void load_ephemeris(::game& ctx)
  175. {
  176. ctx.orbit_system->set_ephemeris(ctx.resource_manager->load<physics::orbit::ephemeris<double>>("de421.eph"));
  177. }
  178. void create_stars(::game& ctx)
  179. {
  180. debug::log_trace("Generating fixed stars...");
  181. // Load star catalog
  182. auto star_catalog = ctx.resource_manager->load<i18n::string_table>("hipparcos-7.tsv");
  183. // Allocate star catalog vertex data
  184. std::size_t star_count = 0;
  185. if (star_catalog->rows.size() > 0)
  186. star_count = star_catalog->rows.size() - 1;
  187. constexpr std::size_t star_vertex_stride = 7 * sizeof(float);
  188. std::vector<float> star_vertex_data(star_count * star_vertex_stride / sizeof(float));
  189. float* star_vertex = star_vertex_data.data();
  190. // Init starlight illuminance
  191. math::dvec3 starlight_illuminance = {0, 0, 0};
  192. // Build star catalog vertex data
  193. for (std::size_t i = 1; i < star_catalog->rows.size(); ++i)
  194. {
  195. const auto& row = star_catalog->rows[i];
  196. // Parse star catalog item
  197. float ra = 0.0;
  198. float dec = 0.0;
  199. float vmag = 0.0;
  200. float bv = 0.0;
  201. try
  202. {
  203. ra = std::stof(row[1]);
  204. dec = std::stof(row[2]);
  205. vmag = std::stof(row[3]);
  206. bv = std::stof(row[4]);
  207. }
  208. catch (const std::exception&)
  209. {
  210. debug::log_warning("Invalid star catalog item on row {}", i);
  211. continue;
  212. }
  213. // Convert right ascension and declination from degrees to radians
  214. ra = math::wrap_radians(math::radians(ra));
  215. dec = math::wrap_radians(math::radians(dec));
  216. // Convert ICRF coordinates from spherical to Cartesian
  217. math::fvec3 position = physics::orbit::frame::bci::cartesian(math::fvec3{1.0f, dec, ra});
  218. // Convert color index to color temperature
  219. float cct = color::bv_to_cct(bv);
  220. // Calculate XYZ color from color temperature
  221. math::fvec3 color_xyz = color::cct_to_xyz(cct);
  222. // Transform XYZ color to RGB
  223. math::fvec3 color_rgb = config::scene_linear_color_space<float>.from_xyz * color_xyz;
  224. // Convert apparent magnitude to brightness factor relative to a 0th magnitude star
  225. float brightness = physics::light::vmag::to_brightness(vmag);
  226. // Build vertex
  227. *(star_vertex++) = position.x();
  228. *(star_vertex++) = position.y();
  229. *(star_vertex++) = position.z();
  230. *(star_vertex++) = color_rgb.x();
  231. *(star_vertex++) = color_rgb.y();
  232. *(star_vertex++) = color_rgb.z();
  233. *(star_vertex++) = brightness;
  234. // Calculate spectral illuminance
  235. math::dvec3 illuminance = math::dvec3(color_rgb * physics::light::vmag::to_illuminance(vmag));
  236. // Add spectral illuminance to total starlight illuminance
  237. starlight_illuminance += illuminance;
  238. }
  239. // Allocate stars model
  240. std::shared_ptr<render::model> stars_model = std::make_shared<render::model>();
  241. // Construct stars VAO
  242. constexpr gl::vertex_input_attribute star_vertex_attributes[] =
  243. {
  244. {
  245. render::vertex_attribute_location::position,
  246. 0,
  247. gl::format::r32g32b32_sfloat,
  248. 0
  249. },
  250. {
  251. render::vertex_attribute_location::color,
  252. 0,
  253. gl::format::r32g32b32a32_sfloat,
  254. 3 * sizeof(float)
  255. }
  256. };
  257. auto& vao = stars_model->get_vertex_array();
  258. vao = std::make_unique<gl::vertex_array>(star_vertex_attributes);
  259. // Construct stars VBO
  260. auto& vbo = stars_model->get_vertex_buffer();
  261. vbo = std::make_unique<gl::vertex_buffer>(gl::buffer_usage::static_draw, std::as_bytes(std::span{star_vertex_data}));
  262. stars_model->set_vertex_offset(0);
  263. stars_model->set_vertex_stride(star_vertex_stride);
  264. // Construct star model group
  265. stars_model->get_groups().resize(1);
  266. render::model_group& stars_model_group = stars_model->get_groups().front();
  267. stars_model_group.id = "stars";
  268. stars_model_group.material = ctx.resource_manager->load<render::material>("fixed-star.mtl");
  269. stars_model_group.primitive_topology = gl::primitive_topology::point_list;
  270. stars_model_group.first_vertex = 0;
  271. stars_model_group.vertex_count = static_cast<std::uint32_t>(star_count);
  272. // Pass stars model to sky pass
  273. ctx.sky_pass->set_stars_model(stars_model);
  274. // Pass starlight illuminance to astronomy system
  275. ctx.astronomy_system->set_starlight_illuminance(starlight_illuminance);
  276. debug::log_trace("Generated fixed stars");
  277. }
  278. void create_sun(::game& ctx)
  279. {
  280. debug::log_trace("Generating Sun...");
  281. {
  282. // Create sun entity
  283. auto sun_archetype = ctx.resource_manager->load<entity::archetype>("sun.ent");
  284. entity::id sun_eid = sun_archetype->create(*ctx.entity_registry);
  285. ctx.entities["sun"] = sun_eid;
  286. // Create sun directional light scene object
  287. ctx.sun_light = std::make_unique<scene::directional_light>();
  288. ctx.sun_light->set_shadow_caster(true);
  289. ctx.sun_light->set_shadow_framebuffer(ctx.shadow_map_framebuffer);
  290. ctx.sun_light->set_shadow_bias(0.005f);
  291. ctx.sun_light->set_shadow_max_distance(20.0f);
  292. ctx.sun_light->set_shadow_fade_range(5.0f);
  293. ctx.sun_light->set_shadow_cascade_count(4);
  294. ctx.sun_light->set_shadow_cascade_distribution(0.8f);
  295. // Add sun light scene objects to surface scene
  296. ctx.surface_scene->add_object(*ctx.sun_light);
  297. // Pass direct sun light scene object to shadow map pass and astronomy system
  298. ctx.astronomy_system->set_sun_light(ctx.sun_light.get());
  299. }
  300. debug::log_trace("Generated Sun");
  301. }
  302. void create_earth_moon_system(::game& ctx)
  303. {
  304. debug::log_trace("Generating Earth-Moon system...");
  305. {
  306. // Create Earth-Moon barycenter entity
  307. auto em_bary_archetype = ctx.resource_manager->load<entity::archetype>("em-bary.ent");
  308. entity::id em_bary_eid = em_bary_archetype->create(*ctx.entity_registry);
  309. ctx.entities["em_bary"] = em_bary_eid;
  310. // Create Earth
  311. create_earth(ctx);
  312. // Create Moon
  313. create_moon(ctx);
  314. }
  315. debug::log_trace("Generated Earth-Moon system");
  316. }
  317. void create_earth(::game& ctx)
  318. {
  319. debug::log_trace("Generating Earth...");
  320. {
  321. // Create earth entity
  322. auto earth_archetype = ctx.resource_manager->load<entity::archetype>("earth.ent");
  323. entity::id earth_eid = earth_archetype->create(*ctx.entity_registry);
  324. ctx.entities["earth"] = earth_eid;
  325. // Assign orbital parent
  326. ctx.entity_registry->get<::orbit_component>(earth_eid).parent = ctx.entities["em_bary"];
  327. }
  328. debug::log_trace("Generated Earth");
  329. }
  330. void create_moon(::game& ctx)
  331. {
  332. debug::log_trace("Generating Moon...");
  333. {
  334. // Create lunar entity
  335. auto moon_archetype = ctx.resource_manager->load<entity::archetype>("moon.ent");
  336. entity::id moon_eid = moon_archetype->create(*ctx.entity_registry);
  337. ctx.entities["moon"] = moon_eid;
  338. // Assign orbital parent
  339. ctx.entity_registry->get<::orbit_component>(moon_eid).parent = ctx.entities["em_bary"];
  340. // Pass moon model to sky pass
  341. ctx.sky_pass->set_moon_model(ctx.resource_manager->load<render::model>("moon.mdl"));
  342. // Create moon directional light scene object
  343. ctx.moon_light = std::make_unique<scene::directional_light>();
  344. // Add moon light scene objects to surface scene
  345. ctx.surface_scene->add_object(*ctx.moon_light);
  346. // Pass moon light scene object to astronomy system
  347. ctx.astronomy_system->set_moon_light(ctx.moon_light.get());
  348. }
  349. debug::log_trace("Generated Moon");
  350. }
  351. void enter_ecoregion(::game& ctx, const ecoregion& ecoregion)
  352. {
  353. debug::log_trace("Entering ecoregion {}...", ecoregion.name);
  354. {
  355. // Set active ecoregion
  356. //ctx.active_ecoregion = &ecoregion;
  357. // Set location
  358. ::world::set_location(ctx, ecoregion.elevation, ecoregion.latitude, ecoregion.longitude);
  359. // Setup sky
  360. ctx.sky_pass->set_sky_model(ctx.resource_manager->load<render::model>("celestial-hemisphere.mdl"));
  361. ctx.sky_pass->set_ground_albedo(ecoregion.terrain_albedo);
  362. // Setup terrain
  363. // ctx.terrain_system->set_patch_material(ecoregion.terrain_material);
  364. // ctx.terrain_system->set_elevation_function
  365. // (
  366. // [](float x, float z) -> float
  367. // {
  368. // const math::fvec2 position = math::fvec2{x, z};
  369. // const std::size_t octaves = 3;
  370. // const float lacunarity = 1.5f;
  371. // const float gain = 0.5f;
  372. // const float fbm = math::noise::fbm
  373. // (
  374. // position * 0.005f,
  375. // octaves,
  376. // lacunarity,
  377. // gain
  378. // );
  379. // float y = fbm * 4.0f;
  380. // return y;
  381. // }
  382. // );
  383. }
  384. debug::log_trace("Entered ecoregion {}", ecoregion.name);
  385. }
  386. void switch_scene(::game& ctx)
  387. {
  388. ctx.fade_transition_color->set({0, 0, 0});
  389. ctx.fade_transition->transition(1.0f, false, ease<float>::out_cubic, false, [](){});
  390. }
  391. } // namespace world