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

609 lines
19 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.find("toggle_fullscreen") == ctx->controls.end())
  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.find("screenshot") == ctx->controls.end())
  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.find("menu_back") == ctx->controls.end())
  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.find("dolly_forward") == ctx->controls.end())
  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.find("dolly_backward") == ctx->controls.end())
  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.find("truck_left") == ctx->controls.end())
  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.find("truck_right") == ctx->controls.end())
  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.find("pedestal_up") == ctx->controls.end())
  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.find("pedestal_down") == ctx->controls.end())
  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.find("move_slow") == ctx->controls.end())
  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.find("move_fast") == ctx->controls.end())
  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.find("mouse_rotate") == ctx->controls.end())
  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.find("mouse_left") == ctx->controls.end())
  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.find("mouse_right") == ctx->controls.end())
  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.find("mouse_up") == ctx->controls.end())
  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.find("mouse_down") == ctx->controls.end())
  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. auto sun_eid = entity::command::create(*ctx->entity_registry, "sun");
  329. // Assign solar celestial body component
  330. entity::component::celestial_body body;
  331. body.radius = 6.957e+8;
  332. body.axial_tilt = math::radians(0.0);
  333. body.axial_rotation = math::radians(0.0);
  334. body.angular_frequency = math::radians(0.0);
  335. ctx->entity_registry->assign<entity::component::celestial_body>(sun_eid, body);
  336. // Assign solar orbit component
  337. entity::component::orbit orbit;
  338. orbit.elements.a = 0.0;
  339. orbit.elements.e = 0.0;
  340. orbit.elements.i = math::radians(0.0);
  341. orbit.elements.raan = math::radians(0.0);
  342. orbit.elements.w = math::radians(0.0);
  343. orbit.elements.ta = math::radians(0.0);
  344. ctx->entity_registry->assign<entity::component::orbit>(sun_eid, orbit);
  345. // Assign solar blackbody component
  346. entity::component::blackbody blackbody;
  347. blackbody.temperature = 5778.0;
  348. ctx->entity_registry->assign<entity::component::blackbody>(sun_eid, blackbody);
  349. // Assign solar transform component
  350. entity::component::transform transform;
  351. transform.local = math::identity_transform<float>;
  352. transform.warp = true;
  353. ctx->entity_registry->assign<entity::component::transform>(sun_eid, transform);
  354. // Create direct sun light scene object
  355. scene::directional_light* sun_direct = new scene::directional_light();
  356. // Create ambient sun light scene object
  357. scene::ambient_light* sun_ambient = new scene::ambient_light();
  358. sun_ambient->set_color({1, 1, 1});
  359. sun_ambient->set_intensity(0.0f);
  360. sun_ambient->update_tweens();
  361. // Add sun light scene objects to surface scene
  362. ctx->surface_scene->add_object(sun_direct);
  363. ctx->surface_scene->add_object(sun_ambient);
  364. // Pass direct sun light scene object to shadow map pass and astronomy system
  365. ctx->surface_shadow_map_pass->set_light(sun_direct);
  366. ctx->astronomy_system->set_sun_light(sun_direct);
  367. }
  368. void planetogenesis(game::context* ctx)
  369. {
  370. // Create planetary entity
  371. auto planet_eid = entity::command::create(*ctx->entity_registry, "planet");
  372. // Assign planetary celestial body component
  373. entity::component::celestial_body body;
  374. body.radius = 6.3781e6;
  375. body.axial_tilt = math::radians(23.4393);
  376. body.axial_rotation = math::radians(280.46061837504);
  377. body.angular_frequency = math::radians(360.9856122880876128);
  378. ctx->entity_registry->assign<entity::component::celestial_body>(planet_eid, body);
  379. // Assign planetary orbit component
  380. entity::component::orbit orbit;
  381. orbit.elements.a = 1.496e+11;
  382. orbit.elements.e = 0.01671123;
  383. orbit.elements.i = math::radians(-0.00001531);
  384. orbit.elements.raan = math::radians(0.0);
  385. const double longitude_periapsis = math::radians(102.93768193);
  386. orbit.elements.w = longitude_periapsis - orbit.elements.raan;
  387. orbit.elements.ta = math::radians(100.46457166) - longitude_periapsis;
  388. ctx->entity_registry->assign<entity::component::orbit>(planet_eid, orbit);
  389. // Assign planetary terrain component
  390. entity::component::terrain terrain;
  391. terrain.elevation = [](double, double) -> double
  392. {
  393. //return math::random<double>(0.0, 1.0);
  394. return 0.0;
  395. };
  396. terrain.max_lod = 0;
  397. terrain.patch_material = nullptr;
  398. ctx->entity_registry->assign<entity::component::terrain>(planet_eid, terrain);
  399. // Assign planetary atmosphere component
  400. entity::component::atmosphere atmosphere;
  401. atmosphere.exosphere_altitude = 65e3;
  402. atmosphere.index_of_refraction = 1.000293;
  403. atmosphere.rayleigh_density = 2.545e25;
  404. atmosphere.rayleigh_scale_height = 8000.0;
  405. atmosphere.mie_density = 14.8875;
  406. atmosphere.mie_scale_height = 1200.0;
  407. atmosphere.mie_anisotropy = 0.8;
  408. ctx->entity_registry->assign<entity::component::atmosphere>(planet_eid, atmosphere);
  409. // Assign planetary transform component
  410. entity::component::transform transform;
  411. transform.local = math::identity_transform<float>;
  412. transform.warp = true;
  413. ctx->entity_registry->assign<entity::component::transform>(planet_eid, transform);
  414. // Pass planet to astronomy system as reference body
  415. ctx->astronomy_system->set_reference_body(planet_eid);
  416. // Load sky model
  417. ctx->surface_sky_pass->set_sky_model(ctx->resource_manager->load<model>("sky-dome.mdl"));
  418. }
  419. void selenogenesis(game::context* ctx)
  420. {
  421. // Create lunar entity
  422. auto moon_eid = entity::command::create(*ctx->entity_registry, "moon");
  423. // Pass moon model to sky pass
  424. ctx->surface_sky_pass->set_moon_model(ctx->resource_manager->load<model>("moon.mdl"));
  425. }
  426. void extrasolar_heliogenesis(game::context* ctx)
  427. {
  428. // Load star catalog
  429. string_table* star_catalog = ctx->resource_manager->load<string_table>("stars.csv");
  430. // Allocate star catalog vertex data
  431. std::size_t star_count = 0;
  432. if (star_catalog->size() > 0)
  433. star_count = star_catalog->size() - 1;
  434. std::size_t star_vertex_size = 6;
  435. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  436. float* star_vertex_data = new float[star_count * star_vertex_size];
  437. float* star_vertex = star_vertex_data;
  438. // Build star catalog vertex data
  439. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  440. {
  441. const string_table_row& catalog_row = (*star_catalog)[i];
  442. double ra = 0.0;
  443. double dec = 0.0;
  444. double vmag = 0.0;
  445. double bv_color = 0.0;
  446. // Parse star catalog entry
  447. try
  448. {
  449. ra = std::stod(catalog_row[1]);
  450. dec = std::stod(catalog_row[2]);
  451. vmag = std::stod(catalog_row[3]);
  452. bv_color = std::stod(catalog_row[4]);
  453. }
  454. catch (const std::exception& e)
  455. {
  456. continue;
  457. }
  458. // Convert right ascension and declination from degrees to radians
  459. ra = math::wrap_radians(math::radians(ra));
  460. dec = math::wrap_radians(math::radians(dec));
  461. // Transform spherical equatorial coordinates to rectangular equatorial coordinates
  462. double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra});
  463. // Transform coordinates from equatorial space to inertial space
  464. physics::frame<double> bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse();
  465. double3 position_inertial = bci_to_inertial * position_bci;
  466. // Convert color index to color temperature
  467. double cct = color::index::bv_to_cct(bv_color);
  468. // Calculate XYZ color from color temperature
  469. double3 color_xyz = color::cct::to_xyz(cct);
  470. // Transform XYZ color to ACEScg colorspace
  471. double3 color_acescg = color::xyz::to_acescg(color_xyz);
  472. // Convert apparent magnitude to irradiance (W/m^2)
  473. double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4));
  474. // Convert irradiance to illuminance
  475. double vmag_illuminance = vmag_irradiance * (683.0 * 0.14);
  476. // Scale color by illuminance
  477. double3 scaled_color = color_acescg * vmag_illuminance;
  478. // Build vertex
  479. *(star_vertex++) = static_cast<float>(position_inertial.x);
  480. *(star_vertex++) = static_cast<float>(position_inertial.y);
  481. *(star_vertex++) = static_cast<float>(position_inertial.z);
  482. *(star_vertex++) = static_cast<float>(scaled_color.x);
  483. *(star_vertex++) = static_cast<float>(scaled_color.y);
  484. *(star_vertex++) = static_cast<float>(scaled_color.z);
  485. }
  486. // Unload star catalog
  487. ctx->resource_manager->unload("stars.csv");
  488. // Allocate stars model
  489. model* stars_model = new model();
  490. // Resize model VBO and upload vertex data
  491. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  492. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  493. // Free star catalog vertex data
  494. delete[] star_vertex_data;
  495. // Bind vertex attributes to model VAO
  496. gl::vertex_array* vao = stars_model->get_vertex_array();
  497. std::size_t vao_offset = 0;
  498. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, 0);
  499. vao_offset += 3;
  500. vao->bind_attribute(VERTEX_COLOR_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, sizeof(float) * vao_offset);
  501. // Load star material
  502. material* star_material = ctx->resource_manager->load<material>("fixed-star.mtl");
  503. // Create model group
  504. model_group* stars_model_group = stars_model->add_group("stars");
  505. stars_model_group->set_material(star_material);
  506. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  507. stars_model_group->set_start_index(0);
  508. stars_model_group->set_index_count(star_count);
  509. // Pass stars model to sky pass
  510. ctx->surface_sky_pass->set_stars_model(stars_model);
  511. }
  512. void colonigenesis(game::context* ctx)
  513. {
  514. // Create queen entity
  515. auto queen_eid = entity::command::create(*ctx->entity_registry, "queen");
  516. // Create central shaft entity
  517. auto shaft_eid = entity::command::create(*ctx->entity_registry, "shaft");
  518. // Create entrance "lobby" chamber entity
  519. auto lobby_eid = entity::command::create(*ctx->entity_registry, "lobby");
  520. }
  521. } // namespace loading
  522. } // namespace state
  523. } // namespace game