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

528 lines
15 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/world.hpp"
  20. #include "scene/text.hpp"
  21. #include "physics/light/vmag.hpp"
  22. #include "color/color.hpp"
  23. #include "game/component/atmosphere.hpp"
  24. #include "game/component/blackbody.hpp"
  25. #include "game/component/celestial-body.hpp"
  26. #include "game/component/orbit.hpp"
  27. #include "game/component/terrain.hpp"
  28. #include "game/component/transform.hpp"
  29. #include "game/component/observer.hpp"
  30. #include "game/system/astronomy.hpp"
  31. #include "game/system/orbit.hpp"
  32. #include "game/system/atmosphere.hpp"
  33. #include "entity/commands.hpp"
  34. #include "entity/archetype.hpp"
  35. #include "geom/spherical.hpp"
  36. #include "gl/drawing-mode.hpp"
  37. #include "gl/vertex-array.hpp"
  38. #include "gl/vertex-attribute.hpp"
  39. #include "gl/vertex-buffer.hpp"
  40. #include "physics/light/photometry.hpp"
  41. #include "physics/orbit/orbit.hpp"
  42. #include "physics/orbit/ephemeris.hpp"
  43. #include "physics/time/gregorian.hpp"
  44. #include "physics/time/constants.hpp"
  45. #include "physics/time/utc.hpp"
  46. #include "render/material.hpp"
  47. #include "render/model.hpp"
  48. #include "render/passes/shadow-map-pass.hpp"
  49. #include "render/vertex-attribute.hpp"
  50. #include "resources/resource-manager.hpp"
  51. #include "scene/ambient-light.hpp"
  52. #include "scene/directional-light.hpp"
  53. #include "gl/texture-wrapping.hpp"
  54. #include "gl/texture-filter.hpp"
  55. #include "render/material-flags.hpp"
  56. #include "geom/solid-angle.hpp"
  57. #include "config.hpp"
  58. #include <iostream>
  59. namespace game {
  60. namespace world {
  61. /// Loads an ephemeris.
  62. static void load_ephemeris(game::context& ctx);
  63. /// Creates the fixed stars.
  64. static void create_stars(game::context& ctx);
  65. /// Creates the Sun.
  66. static void create_sun(game::context& ctx);
  67. /// Creates the Earth-Moon system.
  68. static void create_earth_moon_system(game::context& ctx);
  69. /// Creates the Earth.
  70. static void create_earth(game::context& ctx);
  71. /// Creates the Moon.
  72. static void create_moon(game::context& ctx);
  73. void cosmogenesis(game::context& ctx)
  74. {
  75. ctx.logger->push_task("Generating cosmos");
  76. load_ephemeris(ctx);
  77. create_stars(ctx);
  78. create_sun(ctx);
  79. create_earth_moon_system(ctx);
  80. ctx.logger->pop_task(EXIT_SUCCESS);
  81. }
  82. void create_observer(game::context& ctx)
  83. {
  84. ctx.logger->push_task("Creating observer");
  85. try
  86. {
  87. // Create observer entity
  88. entity::id observer_eid = ctx.entity_registry->create();
  89. ctx.entities["observer"] = observer_eid;
  90. // Construct observer component
  91. game::component::observer observer;
  92. // Set observer reference body
  93. if (auto it = ctx.entities.find("earth"); it != ctx.entities.end())
  94. observer.reference_body_eid = it->second;
  95. else
  96. observer.reference_body_eid = entt::null;
  97. // Set observer location
  98. observer.elevation = 0.0;
  99. observer.latitude = 0.0;
  100. observer.longitude = 0.0;
  101. // Assign observer component to observer entity
  102. ctx.entity_registry->emplace<game::component::observer>(observer_eid, observer);
  103. // Set atmosphere system active atmosphere
  104. ctx.atmosphere_system->set_active_atmosphere(observer.reference_body_eid);
  105. // Set astronomy system observer
  106. ctx.astronomy_system->set_observer(observer_eid);
  107. }
  108. catch (const std::exception&)
  109. {
  110. ctx.logger->pop_task(EXIT_FAILURE);
  111. return;
  112. }
  113. ctx.logger->pop_task(EXIT_SUCCESS);
  114. }
  115. void set_location(game::context& ctx, double elevation, double latitude, double longitude)
  116. {
  117. if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
  118. {
  119. entity::id observer_eid = it->second;
  120. if (ctx.entity_registry->valid(observer_eid) && ctx.entity_registry->all_of<game::component::observer>(observer_eid))
  121. {
  122. // Update observer location
  123. ctx.entity_registry->patch<game::component::observer>
  124. (
  125. observer_eid,
  126. [&](auto& component)
  127. {
  128. component.elevation = elevation;
  129. component.latitude = latitude;
  130. component.longitude = longitude;
  131. }
  132. );
  133. }
  134. }
  135. }
  136. void set_time(game::context& ctx, double t)
  137. {
  138. ctx.logger->push_task("Setting time to UT1 " + std::to_string(t));
  139. try
  140. {
  141. ctx.astronomy_system->set_time(t);
  142. ctx.orbit_system->set_time(t);
  143. }
  144. catch (const std::exception&)
  145. {
  146. ctx.logger->pop_task(EXIT_FAILURE);
  147. return;
  148. }
  149. ctx.logger->pop_task(EXIT_SUCCESS);
  150. }
  151. void set_time(game::context& ctx, int year, int month, int day, int hour, int minute, double second)
  152. {
  153. double longitude = 0.0;
  154. // Get longitude of observer
  155. if (auto it = ctx.entities.find("observer"); it != ctx.entities.end())
  156. {
  157. entity::id observer_eid = it->second;
  158. if (ctx.entity_registry->valid(observer_eid))
  159. {
  160. const auto observer = ctx.entity_registry->try_get<game::component::observer>(observer_eid);
  161. if (observer)
  162. longitude = observer->longitude;
  163. }
  164. }
  165. // Calculate UTC offset at longitude
  166. const double utc_offset = physics::time::utc::offset<double>(longitude);
  167. // Convert time from Gregorian to UT1
  168. const double t = physics::time::gregorian::to_ut1<double>(year, month, day, hour, minute, second, utc_offset);
  169. set_time(ctx, t);
  170. }
  171. void set_time_scale(game::context& ctx, double scale)
  172. {
  173. // Convert time scale from seconds to days
  174. const double astronomical_scale = scale / physics::time::seconds_per_day<double>;
  175. ctx.orbit_system->set_time_scale(astronomical_scale);
  176. ctx.astronomy_system->set_time_scale(astronomical_scale);
  177. }
  178. void load_ephemeris(game::context& ctx)
  179. {
  180. ctx.logger->push_task("Loading ephemeris");
  181. try
  182. {
  183. std::string ephemeris_filename;
  184. if (ctx.config->contains("ephemeris"))
  185. {
  186. ephemeris_filename = (*ctx.config)["ephemeris"].get<std::string>();
  187. }
  188. else
  189. {
  190. ctx.logger->warning("No ephemeris set in config");
  191. ctx.logger->pop_task(EXIT_FAILURE);
  192. return;
  193. }
  194. ctx.orbit_system->set_ephemeris(ctx.resource_manager->load<physics::orbit::ephemeris<double>>(ephemeris_filename));
  195. }
  196. catch (const std::exception&)
  197. {
  198. ctx.logger->pop_task(EXIT_FAILURE);
  199. return;
  200. }
  201. ctx.logger->pop_task(EXIT_SUCCESS);
  202. }
  203. void create_stars(game::context& ctx)
  204. {
  205. ctx.logger->push_task("Generating fixed stars");
  206. // Load star catalog
  207. string_table* star_catalog = nullptr;
  208. try
  209. {
  210. std::string star_catalog_filename;
  211. if (ctx.config->contains("star_catalog"))
  212. {
  213. star_catalog_filename = (*ctx.config)["star_catalog"].get<std::string>();
  214. }
  215. else
  216. {
  217. ctx.logger->warning("No star catalog set in config");
  218. ctx.logger->pop_task(EXIT_FAILURE);
  219. return;
  220. }
  221. star_catalog = ctx.resource_manager->load<string_table>(star_catalog_filename);
  222. }
  223. catch (const std::exception&)
  224. {
  225. ctx.logger->pop_task(EXIT_FAILURE);
  226. return;
  227. }
  228. // Allocate star catalog vertex data
  229. std::size_t star_count = 0;
  230. if (star_catalog->size() > 0)
  231. star_count = star_catalog->size() - 1;
  232. std::size_t star_vertex_size = 7;
  233. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  234. float* star_vertex_data = new float[star_count * star_vertex_size];
  235. float* star_vertex = star_vertex_data;
  236. // Init starlight illuminance
  237. double3 starlight_illuminance = {0, 0, 0};
  238. // Build star catalog vertex data
  239. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  240. {
  241. const string_table_row& catalog_row = (*star_catalog)[i];
  242. // Parse star catalog item
  243. double ra = 0.0;
  244. double dec = 0.0;
  245. double vmag = 0.0;
  246. double bv = 0.0;
  247. try
  248. {
  249. ra = std::stod(catalog_row[1]);
  250. dec = std::stod(catalog_row[2]);
  251. vmag = std::stod(catalog_row[3]);
  252. bv = std::stod(catalog_row[4]);
  253. }
  254. catch (const std::exception&)
  255. {
  256. ctx.logger->warning("Invalid star catalog item on row " + std::to_string(i));
  257. }
  258. // Convert right ascension and declination from degrees to radians
  259. ra = math::wrap_radians(math::radians(ra));
  260. dec = math::wrap_radians(math::radians(dec));
  261. // Convert ICRF coordinates from spherical to Cartesian
  262. double3 position = physics::orbit::frame::bci::cartesian(double3{1.0, dec, ra});
  263. // Convert color index to color temperature
  264. double cct = color::index::bv_to_cct(bv);
  265. // Calculate XYZ color from color temperature
  266. double3 color_xyz = color::cct::to_xyz(cct);
  267. // Transform XYZ color to ACEScg colorspace
  268. double3 color_acescg = color::aces::ap1<double>.from_xyz * color_xyz;
  269. // Convert apparent magnitude to brightness factor relative to a 0th magnitude star
  270. double brightness = physics::light::vmag::to_brightness(vmag);
  271. // Build vertex
  272. *(star_vertex++) = static_cast<float>(position.x());
  273. *(star_vertex++) = static_cast<float>(position.y());
  274. *(star_vertex++) = static_cast<float>(position.z());
  275. *(star_vertex++) = static_cast<float>(color_acescg.x());
  276. *(star_vertex++) = static_cast<float>(color_acescg.y());
  277. *(star_vertex++) = static_cast<float>(color_acescg.z());
  278. *(star_vertex++) = static_cast<float>(brightness);
  279. // Calculate spectral illuminance
  280. double3 illuminance = color_acescg * physics::light::vmag::to_illuminance(vmag);
  281. // Add spectral illuminance to total starlight illuminance
  282. starlight_illuminance += illuminance;
  283. }
  284. // Unload star catalog
  285. ctx.resource_manager->unload("stars.csv");
  286. // Allocate stars model
  287. render::model* stars_model = new render::model();
  288. // Get model VBO and VAO
  289. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  290. gl::vertex_array* vao = stars_model->get_vertex_array();
  291. // Resize model VBO and upload vertex data
  292. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  293. // Free star catalog vertex data
  294. delete[] star_vertex_data;
  295. std::size_t attribute_offset = 0;
  296. // Define position vertex attribute
  297. gl::vertex_attribute position_attribute;
  298. position_attribute.buffer = vbo;
  299. position_attribute.offset = attribute_offset;
  300. position_attribute.stride = star_vertex_stride;
  301. position_attribute.type = gl::vertex_attribute_type::float_32;
  302. position_attribute.components = 3;
  303. attribute_offset += position_attribute.components * sizeof(float);
  304. // Define color vertex attribute
  305. gl::vertex_attribute color_attribute;
  306. color_attribute.buffer = vbo;
  307. color_attribute.offset = attribute_offset;
  308. color_attribute.stride = star_vertex_stride;
  309. color_attribute.type = gl::vertex_attribute_type::float_32;
  310. color_attribute.components = 4;
  311. attribute_offset += color_attribute.components * sizeof(float);
  312. // Bind vertex attributes to VAO
  313. vao->bind(render::vertex_attribute::position, position_attribute);
  314. vao->bind(render::vertex_attribute::color, color_attribute);
  315. // Load star material
  316. render::material* star_material = ctx.resource_manager->load<render::material>("fixed-star.mtl");
  317. // Create model group
  318. render::model_group* stars_model_group = stars_model->add_group("stars");
  319. stars_model_group->set_material(star_material);
  320. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  321. stars_model_group->set_start_index(0);
  322. stars_model_group->set_index_count(star_count);
  323. // Pass stars model to sky pass
  324. ctx.sky_pass->set_stars_model(stars_model);
  325. // Pass starlight illuminance to astronomy system
  326. ctx.astronomy_system->set_starlight_illuminance(starlight_illuminance);
  327. ctx.logger->pop_task(EXIT_SUCCESS);
  328. }
  329. void create_sun(game::context& ctx)
  330. {
  331. ctx.logger->push_task("Generating Sun");
  332. try
  333. {
  334. // Create sun entity
  335. entity::archetype* sun_archetype = ctx.resource_manager->load<entity::archetype>("sun.ent");
  336. entity::id sun_eid = sun_archetype->create(*ctx.entity_registry);
  337. ctx.entities["sun"] = sun_eid;
  338. // Create sun directional light scene object
  339. scene::directional_light* sun_light = new scene::directional_light();
  340. sun_light->set_color({0, 0, 0});
  341. sun_light->update_tweens();
  342. // Create sky ambient light scene object
  343. scene::ambient_light* sky_light = new scene::ambient_light();
  344. sky_light->set_color({0, 0, 0});
  345. sky_light->update_tweens();
  346. // Create bounce directional light scene object
  347. scene::directional_light* bounce_light = new scene::directional_light();
  348. bounce_light->set_color({0, 0, 0});
  349. bounce_light->look_at({0, 0, 0}, {0, 1, 0}, {1, 0, 0});
  350. bounce_light->update_tweens();
  351. // Add sun light scene objects to surface scene
  352. ctx.surface_scene->add_object(sun_light);
  353. ctx.surface_scene->add_object(sky_light);
  354. //ctx.surface_scene->add_object(bounce_light);
  355. // Pass direct sun light scene object to shadow map pass and astronomy system
  356. ctx.surface_shadow_map_pass->set_light(sun_light);
  357. ctx.astronomy_system->set_sun_light(sun_light);
  358. ctx.astronomy_system->set_sky_light(sky_light);
  359. ctx.astronomy_system->set_bounce_light(bounce_light);
  360. }
  361. catch (const std::exception&)
  362. {
  363. ctx.logger->pop_task(EXIT_FAILURE);
  364. return;
  365. }
  366. ctx.logger->pop_task(EXIT_SUCCESS);
  367. }
  368. void create_earth_moon_system(game::context& ctx)
  369. {
  370. ctx.logger->push_task("Generating Earth-Moon system");
  371. try
  372. {
  373. // Create Earth-Moon barycenter entity
  374. entity::archetype* em_bary_archetype = ctx.resource_manager->load<entity::archetype>("em-bary.ent");
  375. entity::id em_bary_eid = em_bary_archetype->create(*ctx.entity_registry);
  376. ctx.entities["em_bary"] = em_bary_eid;
  377. // Create Earth
  378. create_earth(ctx);
  379. // Create Moon
  380. create_moon(ctx);
  381. }
  382. catch (const std::exception&)
  383. {
  384. ctx.logger->pop_task(EXIT_FAILURE);
  385. return;
  386. }
  387. ctx.logger->pop_task(EXIT_SUCCESS);
  388. }
  389. void create_earth(game::context& ctx)
  390. {
  391. ctx.logger->push_task("Generating Earth");
  392. try
  393. {
  394. // Create earth entity
  395. entity::archetype* earth_archetype = ctx.resource_manager->load<entity::archetype>("earth.ent");
  396. entity::id earth_eid = earth_archetype->create(*ctx.entity_registry);
  397. ctx.entities["earth"] = earth_eid;
  398. // Assign orbital parent
  399. ctx.entity_registry->get<game::component::orbit>(earth_eid).parent = ctx.entities["em_bary"];
  400. }
  401. catch (const std::exception&)
  402. {
  403. ctx.logger->pop_task(EXIT_FAILURE);
  404. return;
  405. }
  406. ctx.logger->pop_task(EXIT_SUCCESS);
  407. }
  408. void create_moon(game::context& ctx)
  409. {
  410. ctx.logger->push_task("Generating Moon");
  411. try
  412. {
  413. // Create lunar entity
  414. entity::archetype* moon_archetype = ctx.resource_manager->load<entity::archetype>("moon.ent");
  415. entity::id moon_eid = moon_archetype->create(*ctx.entity_registry);
  416. ctx.entities["moon"] = moon_eid;
  417. // Assign orbital parent
  418. ctx.entity_registry->get<game::component::orbit>(moon_eid).parent = ctx.entities["em_bary"];
  419. // Pass moon model to sky pass
  420. ctx.sky_pass->set_moon_model(ctx.resource_manager->load<render::model>("moon.mdl"));
  421. // Create moon directional light scene object
  422. scene::directional_light* moon_light = new scene::directional_light();
  423. moon_light->set_color({0, 0, 0});
  424. moon_light->update_tweens();
  425. // Add moon light scene objects to surface scene
  426. ctx.surface_scene->add_object(moon_light);
  427. // Pass moon light scene object to astronomy system
  428. ctx.astronomy_system->set_moon_light(moon_light);
  429. }
  430. catch (const std::exception&)
  431. {
  432. ctx.logger->pop_task(EXIT_FAILURE);
  433. return;
  434. }
  435. ctx.logger->pop_task(EXIT_SUCCESS);
  436. }
  437. } // namespace world
  438. } // namespace game