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

602 lines
18 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/states/loading.hpp"
  20. #include "application.hpp"
  21. #include "astro/illuminance.hpp"
  22. #include "color/color.hpp"
  23. #include "entity/components/atmosphere.hpp"
  24. #include "entity/components/blackbody.hpp"
  25. #include "entity/components/celestial-body.hpp"
  26. #include "entity/components/orbit.hpp"
  27. #include "entity/components/terrain.hpp"
  28. #include "entity/components/transform.hpp"
  29. #include "entity/systems/astronomy.hpp"
  30. #include "entity/systems/orbit.hpp"
  31. #include "entity/commands.hpp"
  32. #include "game/states/nuptial-flight.hpp"
  33. #include "game/states/splash.hpp"
  34. #include "geom/spherical.hpp"
  35. #include "gl/drawing-mode.hpp"
  36. #include "gl/vertex-array.hpp"
  37. #include "gl/vertex-attribute-type.hpp"
  38. #include "gl/vertex-buffer.hpp"
  39. #include "physics/light/photometry.hpp"
  40. #include "physics/orbit/orbit.hpp"
  41. #include "renderer/material.hpp"
  42. #include "renderer/model.hpp"
  43. #include "renderer/passes/shadow-map-pass.hpp"
  44. #include "renderer/vertex-attributes.hpp"
  45. #include "resources/resource-manager.hpp"
  46. #include "scene/ambient-light.hpp"
  47. #include "scene/directional-light.hpp"
  48. #include "resources/config-file.hpp"
  49. #include "utility/timestamp.hpp"
  50. namespace game {
  51. namespace state {
  52. namespace loading {
  53. /// Creates or loads control configuration
  54. static void load_controls(game::context* ctx);
  55. /// Creates the universe and solar system.
  56. static void cosmogenesis(game::context* ctx);
  57. /// Creates a sun.
  58. static void heliogenesis(game::context* ctx);
  59. /// Creates a planet.
  60. static void planetogenesis(game::context* ctx);
  61. /// Creates a moon.
  62. static void selenogenesis(game::context* ctx);
  63. /// Creates fixed stars.
  64. static void extrasolar_heliogenesis(game::context* ctx);
  65. /// Creates an ant colony
  66. static void colonigenesis(game::context* ctx);
  67. void enter(game::context* ctx)
  68. {
  69. // Load controls
  70. ctx->logger->push_task("Loading controls");
  71. try
  72. {
  73. load_controls(ctx);
  74. }
  75. catch (...)
  76. {
  77. ctx->logger->pop_task(EXIT_FAILURE);
  78. }
  79. ctx->logger->pop_task(EXIT_SUCCESS);
  80. // Create universe
  81. ctx->logger->push_task("Creating the universe");
  82. try
  83. {
  84. cosmogenesis(ctx);
  85. }
  86. catch (...)
  87. {
  88. ctx->logger->pop_task(EXIT_FAILURE);
  89. throw;
  90. }
  91. ctx->logger->pop_task(EXIT_SUCCESS);
  92. // Determine next game state
  93. application::state next_state;
  94. if (ctx->option_quick_start.has_value())
  95. {
  96. next_state.name = "nuptial flight";
  97. next_state.enter = std::bind(game::state::nuptial_flight::enter, ctx);
  98. next_state.exit = std::bind(game::state::nuptial_flight::exit, ctx);
  99. }
  100. else
  101. {
  102. next_state.name = "splash";
  103. next_state.enter = std::bind(game::state::splash::enter, ctx);
  104. next_state.exit = std::bind(game::state::splash::exit, ctx);
  105. }
  106. // Queue next game state
  107. ctx->app->queue_state(next_state);
  108. }
  109. void exit(game::context* ctx)
  110. {}
  111. void load_controls(game::context* ctx)
  112. {
  113. // Toggle fullscreen
  114. if (!ctx->controls.count("toggle_fullscreen"))
  115. {
  116. input::control* control = new input::control();
  117. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::f11));
  118. ctx->controls["toggle_fullscreen"] = control;
  119. }
  120. ctx->controls["toggle_fullscreen"]->set_activated_callback
  121. (
  122. [ctx]()
  123. {
  124. bool fullscreen = !ctx->app->is_fullscreen();
  125. ctx->app->set_fullscreen(fullscreen);
  126. if (!fullscreen)
  127. {
  128. int2 resolution = ctx->config->get<int2>("windowed_resolution");
  129. ctx->app->resize_window(resolution.x, resolution.y);
  130. }
  131. ctx->config->set<int>("fullscreen", (fullscreen) ? 1 : 0);
  132. }
  133. );
  134. // Screenshot
  135. if (!ctx->controls.count("screenshot"))
  136. {
  137. input::control* control = new input::control();
  138. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::f12));
  139. ctx->controls["screenshot"] = control;
  140. }
  141. ctx->controls["screenshot"]->set_activated_callback
  142. (
  143. [ctx]()
  144. {
  145. std::string path = ctx->screenshots_path + "antkeeper-" + timestamp() + ".png";
  146. ctx->app->save_frame(path);
  147. }
  148. );
  149. // Menu back
  150. if (!ctx->controls.count("menu_back"))
  151. {
  152. input::control* control = new input::control();
  153. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::escape));
  154. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::backspace));
  155. ctx->controls["menu_back"] = control;
  156. }
  157. ctx->controls["menu_back"]->set_activated_callback
  158. (
  159. std::bind(&application::close, ctx->app, 0)
  160. );
  161. // Dolly forward
  162. if (!ctx->controls.count("dolly_forward"))
  163. {
  164. input::control* control = new input::control();
  165. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::w));
  166. ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_y, true));
  167. ctx->controls["dolly_forward"] = control;
  168. }
  169. // Dolly backward
  170. if (!ctx->controls.count("dolly_backward"))
  171. {
  172. input::control* control = new input::control();
  173. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::s));
  174. ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_y, false));
  175. ctx->controls["dolly_backward"] = control;
  176. }
  177. // Truck left
  178. if (!ctx->controls.count("truck_left"))
  179. {
  180. input::control* control = new input::control();
  181. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::a));
  182. ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_x, true));
  183. ctx->controls["truck_left"] = control;
  184. }
  185. // Truck right
  186. if (!ctx->controls.count("truck_right"))
  187. {
  188. input::control* control = new input::control();
  189. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::d));
  190. ctx->input_event_router->add_mapping(input::game_controller_axis_mapping(control, nullptr, input::game_controller_axis::left_x, false));
  191. ctx->controls["truck_right"] = control;
  192. }
  193. // Pedestal up
  194. if (!ctx->controls.count("pedestal_up"))
  195. {
  196. input::control* control = new input::control();
  197. ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, input::mouse_wheel_axis::positive_y));
  198. ctx->controls["pedestal_up"] = control;
  199. }
  200. // Pedestal down
  201. if (!ctx->controls.count("pedestal_down"))
  202. {
  203. input::control* control = new input::control();
  204. ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, input::mouse_wheel_axis::negative_y));
  205. ctx->controls["pedestal_down"] = control;
  206. }
  207. // Move slow
  208. if (!ctx->controls.count("move_slow"))
  209. {
  210. input::control* control = new input::control();
  211. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_ctrl));
  212. ctx->controls["move_slow"] = control;
  213. }
  214. // Move fast
  215. if (!ctx->controls.count("move_fast"))
  216. {
  217. input::control* control = new input::control();
  218. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_shift));
  219. ctx->controls["move_fast"] = control;
  220. }
  221. // Mouse rotate
  222. if (!ctx->controls.count("mouse_rotate"))
  223. {
  224. input::control* control = new input::control();
  225. ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, nullptr, 3));
  226. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, input::scancode::left_alt));
  227. ctx->controls["mouse_rotate"] = control;
  228. }
  229. // Mouse left
  230. if (!ctx->controls.count("mouse_left"))
  231. {
  232. input::control* control = new input::control();
  233. ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::negative_x));
  234. ctx->controls["mouse_left"] = control;
  235. }
  236. // Mouse right
  237. if (!ctx->controls.count("mouse_right"))
  238. {
  239. input::control* control = new input::control();
  240. ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::positive_x));
  241. ctx->controls["mouse_right"] = control;
  242. }
  243. // Mouse up
  244. if (!ctx->controls.count("mouse_up"))
  245. {
  246. input::control* control = new input::control();
  247. ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::negative_y));
  248. ctx->controls["mouse_up"] = control;
  249. }
  250. // Mouse down
  251. if (!ctx->controls.count("mouse_down"))
  252. {
  253. input::control* control = new input::control();
  254. ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, input::mouse_motion_axis::positive_y));
  255. ctx->controls["mouse_down"] = control;
  256. }
  257. }
  258. void cosmogenesis(game::context* ctx)
  259. {
  260. // Init time
  261. const double time = 0.0;
  262. ctx->astronomy_system->set_universal_time(time);
  263. ctx->orbit_system->set_universal_time(time);
  264. // Create sun
  265. ctx->logger->push_task("Creating the sun");
  266. try
  267. {
  268. heliogenesis(ctx);
  269. }
  270. catch (...)
  271. {
  272. ctx->logger->pop_task(EXIT_FAILURE);
  273. throw;
  274. }
  275. ctx->logger->pop_task(EXIT_SUCCESS);
  276. // Create planet
  277. ctx->logger->push_task("Creating the planet");
  278. try
  279. {
  280. planetogenesis(ctx);
  281. }
  282. catch (...)
  283. {
  284. ctx->logger->pop_task(EXIT_FAILURE);
  285. throw;
  286. }
  287. ctx->logger->pop_task(EXIT_SUCCESS);
  288. // Create moon
  289. ctx->logger->push_task("Creating the moon");
  290. try
  291. {
  292. selenogenesis(ctx);
  293. }
  294. catch (...)
  295. {
  296. ctx->logger->pop_task(EXIT_FAILURE);
  297. throw;
  298. }
  299. ctx->logger->pop_task(EXIT_SUCCESS);
  300. // Create fixed stars
  301. ctx->logger->push_task("Creating fixed stars");
  302. try
  303. {
  304. extrasolar_heliogenesis(ctx);
  305. }
  306. catch (...)
  307. {
  308. ctx->logger->pop_task(EXIT_FAILURE);
  309. throw;
  310. }
  311. ctx->logger->pop_task(EXIT_SUCCESS);
  312. // Create ant colony
  313. ctx->logger->push_task("Creating ant colony");
  314. try
  315. {
  316. colonigenesis(ctx);
  317. }
  318. catch (...)
  319. {
  320. ctx->logger->pop_task(EXIT_FAILURE);
  321. throw;
  322. }
  323. ctx->logger->pop_task(EXIT_SUCCESS);
  324. }
  325. void heliogenesis(game::context* ctx)
  326. {
  327. // Create solar entity
  328. entity::id sun_eid = ctx->entity_registry->create();
  329. ctx->entities["sun"] = sun_eid;
  330. // Assign solar celestial body component
  331. entity::component::celestial_body body;
  332. body.radius = 6.957e+8;
  333. body.axial_tilt = math::radians(0.0);
  334. body.axial_rotation = math::radians(0.0);
  335. body.angular_frequency = math::radians(0.0);
  336. ctx->entity_registry->assign<entity::component::celestial_body>(sun_eid, body);
  337. // Assign solar orbit component
  338. entity::component::orbit orbit;
  339. orbit.elements.a = 0.0;
  340. orbit.elements.e = 0.0;
  341. orbit.elements.i = math::radians(0.0);
  342. orbit.elements.raan = math::radians(0.0);
  343. orbit.elements.w = math::radians(0.0);
  344. orbit.elements.ta = math::radians(0.0);
  345. ctx->entity_registry->assign<entity::component::orbit>(sun_eid, orbit);
  346. // Assign solar blackbody component
  347. entity::component::blackbody blackbody;
  348. blackbody.temperature = 5778.0;
  349. ctx->entity_registry->assign<entity::component::blackbody>(sun_eid, blackbody);
  350. // Assign solar transform component
  351. entity::component::transform transform;
  352. transform.local = math::identity_transform<float>;
  353. transform.warp = true;
  354. ctx->entity_registry->assign<entity::component::transform>(sun_eid, transform);
  355. // Create direct sun light scene object
  356. scene::directional_light* sun_direct = new scene::directional_light();
  357. // Create ambient sun light scene object
  358. scene::ambient_light* sun_ambient = new scene::ambient_light();
  359. sun_ambient->set_color({1, 1, 1});
  360. sun_ambient->set_intensity(0.0f);
  361. sun_ambient->update_tweens();
  362. // Add sun light scene objects to surface scene
  363. ctx->surface_scene->add_object(sun_direct);
  364. ctx->surface_scene->add_object(sun_ambient);
  365. // Pass direct sun light scene object to shadow map pass and astronomy system
  366. ctx->surface_shadow_map_pass->set_light(sun_direct);
  367. ctx->astronomy_system->set_sun_light(sun_direct);
  368. }
  369. void planetogenesis(game::context* ctx)
  370. {
  371. // Create planetary entity
  372. entity::id planet_eid = ctx->entity_registry->create();
  373. ctx->entities["planet"] = planet_eid;
  374. // Assign planetary celestial body component
  375. entity::component::celestial_body body;
  376. body.radius = 6.3781e6;
  377. body.axial_tilt = math::radians(23.4393);
  378. body.axial_rotation = math::radians(280.46061837504);
  379. body.angular_frequency = math::radians(360.9856122880876128);
  380. ctx->entity_registry->assign<entity::component::celestial_body>(planet_eid, body);
  381. // Assign planetary orbit component
  382. entity::component::orbit orbit;
  383. orbit.elements.a = 1.496e+11;
  384. orbit.elements.e = 0.01671123;
  385. orbit.elements.i = math::radians(-0.00001531);
  386. orbit.elements.raan = math::radians(0.0);
  387. const double longitude_periapsis = math::radians(102.93768193);
  388. orbit.elements.w = longitude_periapsis - orbit.elements.raan;
  389. orbit.elements.ta = math::radians(100.46457166) - longitude_periapsis;
  390. ctx->entity_registry->assign<entity::component::orbit>(planet_eid, orbit);
  391. // Assign planetary terrain component
  392. entity::component::terrain terrain;
  393. terrain.elevation = [](double, double) -> double
  394. {
  395. //return math::random<double>(0.0, 1.0);
  396. return 0.0;
  397. };
  398. terrain.max_lod = 0;
  399. terrain.patch_material = nullptr;
  400. ctx->entity_registry->assign<entity::component::terrain>(planet_eid, terrain);
  401. // Assign planetary atmosphere component
  402. entity::component::atmosphere atmosphere;
  403. atmosphere.exosphere_altitude = 65e3;
  404. atmosphere.index_of_refraction = 1.000293;
  405. atmosphere.rayleigh_density = 2.545e25;
  406. atmosphere.rayleigh_scale_height = 8000.0;
  407. atmosphere.mie_density = 14.8875;
  408. atmosphere.mie_scale_height = 1200.0;
  409. atmosphere.mie_anisotropy = 0.8;
  410. ctx->entity_registry->assign<entity::component::atmosphere>(planet_eid, atmosphere);
  411. // Assign planetary transform component
  412. entity::component::transform transform;
  413. transform.local = math::identity_transform<float>;
  414. transform.warp = true;
  415. ctx->entity_registry->assign<entity::component::transform>(planet_eid, transform);
  416. // Pass planet to astronomy system as reference body
  417. ctx->astronomy_system->set_reference_body(planet_eid);
  418. // Load sky model
  419. ctx->surface_sky_pass->set_sky_model(ctx->resource_manager->load<model>("sky-dome.mdl"));
  420. }
  421. void selenogenesis(game::context* ctx)
  422. {
  423. // Create lunar entity
  424. entity::id moon_eid = ctx->entity_registry->create();
  425. ctx->entities["moon"] = moon_eid;
  426. // Pass moon model to sky pass
  427. ctx->surface_sky_pass->set_moon_model(ctx->resource_manager->load<model>("moon.mdl"));
  428. }
  429. void extrasolar_heliogenesis(game::context* ctx)
  430. {
  431. // Load star catalog
  432. string_table* star_catalog = ctx->resource_manager->load<string_table>("stars.csv");
  433. // Allocate star catalog vertex data
  434. std::size_t star_count = 0;
  435. if (star_catalog->size() > 0)
  436. star_count = star_catalog->size() - 1;
  437. std::size_t star_vertex_size = 6;
  438. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  439. float* star_vertex_data = new float[star_count * star_vertex_size];
  440. float* star_vertex = star_vertex_data;
  441. // Build star catalog vertex data
  442. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  443. {
  444. const string_table_row& catalog_row = (*star_catalog)[i];
  445. double ra = 0.0;
  446. double dec = 0.0;
  447. double vmag = 0.0;
  448. double bv_color = 0.0;
  449. // Parse star catalog entry
  450. try
  451. {
  452. ra = std::stod(catalog_row[1]);
  453. dec = std::stod(catalog_row[2]);
  454. vmag = std::stod(catalog_row[3]);
  455. bv_color = std::stod(catalog_row[4]);
  456. }
  457. catch (const std::exception& e)
  458. {
  459. continue;
  460. }
  461. // Convert right ascension and declination from degrees to radians
  462. ra = math::wrap_radians(math::radians(ra));
  463. dec = math::wrap_radians(math::radians(dec));
  464. // Transform spherical equatorial coordinates to rectangular equatorial coordinates
  465. double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra});
  466. // Transform coordinates from equatorial space to inertial space
  467. physics::frame<double> bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse();
  468. double3 position_inertial = bci_to_inertial * position_bci;
  469. // Convert color index to color temperature
  470. double cct = color::index::bv_to_cct(bv_color);
  471. // Calculate XYZ color from color temperature
  472. double3 color_xyz = color::cct::to_xyz(cct);
  473. // Transform XYZ color to ACEScg colorspace
  474. double3 color_acescg = color::xyz::to_acescg(color_xyz);
  475. // Convert apparent magnitude to irradiance (W/m^2)
  476. double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4));
  477. // Convert irradiance to illuminance
  478. double vmag_illuminance = vmag_irradiance * (683.0 * 0.14);
  479. // Scale color by illuminance
  480. double3 scaled_color = color_acescg * vmag_illuminance;
  481. // Build vertex
  482. *(star_vertex++) = static_cast<float>(position_inertial.x);
  483. *(star_vertex++) = static_cast<float>(position_inertial.y);
  484. *(star_vertex++) = static_cast<float>(position_inertial.z);
  485. *(star_vertex++) = static_cast<float>(scaled_color.x);
  486. *(star_vertex++) = static_cast<float>(scaled_color.y);
  487. *(star_vertex++) = static_cast<float>(scaled_color.z);
  488. }
  489. // Unload star catalog
  490. ctx->resource_manager->unload("stars.csv");
  491. // Allocate stars model
  492. model* stars_model = new model();
  493. // Resize model VBO and upload vertex data
  494. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  495. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  496. // Free star catalog vertex data
  497. delete[] star_vertex_data;
  498. // Bind vertex attributes to model VAO
  499. gl::vertex_array* vao = stars_model->get_vertex_array();
  500. std::size_t vao_offset = 0;
  501. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, 0);
  502. vao_offset += 3;
  503. vao->bind_attribute(VERTEX_COLOR_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, sizeof(float) * vao_offset);
  504. // Load star material
  505. material* star_material = ctx->resource_manager->load<material>("fixed-star.mtl");
  506. // Create model group
  507. model_group* stars_model_group = stars_model->add_group("stars");
  508. stars_model_group->set_material(star_material);
  509. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  510. stars_model_group->set_start_index(0);
  511. stars_model_group->set_index_count(star_count);
  512. // Pass stars model to sky pass
  513. ctx->surface_sky_pass->set_stars_model(stars_model);
  514. }
  515. void colonigenesis(game::context* ctx)
  516. {}
  517. } // namespace loading
  518. } // namespace state
  519. } // namespace game