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

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