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

596 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 "entity/archetype.hpp"
  33. #include "game/states/nuptial-flight.hpp"
  34. #include "game/states/splash.hpp"
  35. #include "game/states/main-menu.hpp"
  36. #include "game/controls.hpp"
  37. #include "geom/spherical.hpp"
  38. #include "gl/drawing-mode.hpp"
  39. #include "gl/vertex-array.hpp"
  40. #include "gl/vertex-attribute.hpp"
  41. #include "gl/vertex-buffer.hpp"
  42. #include "physics/light/photometry.hpp"
  43. #include "physics/orbit/orbit.hpp"
  44. #include "render/material.hpp"
  45. #include "render/model.hpp"
  46. #include "render/passes/shadow-map-pass.hpp"
  47. #include "render/vertex-attribute.hpp"
  48. #include "resources/resource-manager.hpp"
  49. #include "scene/ambient-light.hpp"
  50. #include "scene/directional-light.hpp"
  51. #include "utility/timestamp.hpp"
  52. #include "type/type.hpp"
  53. #include "configuration.hpp"
  54. #include <stb/stb_image_write.h>
  55. #include <unordered_set>
  56. #include <codecvt>
  57. #include "gl/texture-wrapping.hpp"
  58. #include "gl/texture-filter.hpp"
  59. #include "scene/text.hpp"
  60. #include "render/material-flags.hpp"
  61. namespace game {
  62. namespace state {
  63. namespace loading {
  64. /// Loads control profile and calibrates gamepads
  65. static void load_controls(game::context* ctx);
  66. /// Loads typefaces and builds fonts
  67. static void load_fonts(game::context* ctx);
  68. /// Creates the universe and solar system.
  69. static void cosmogenesis(game::context* ctx);
  70. /// Creates a sun.
  71. static void heliogenesis(game::context* ctx);
  72. /// Creates a planet.
  73. static void planetogenesis(game::context* ctx);
  74. /// Creates a moon.
  75. static void selenogenesis(game::context* ctx);
  76. /// Creates fixed stars.
  77. static void extrasolar_heliogenesis(game::context* ctx);
  78. /// Creates an ant colony
  79. static void colonigenesis(game::context* ctx);
  80. void enter(game::context* ctx)
  81. {
  82. // Load controls
  83. ctx->logger->push_task("Loading controls");
  84. try
  85. {
  86. load_controls(ctx);
  87. }
  88. catch (...)
  89. {
  90. ctx->logger->pop_task(EXIT_FAILURE);
  91. }
  92. ctx->logger->pop_task(EXIT_SUCCESS);
  93. // Load fonts
  94. ctx->logger->push_task("Loading fonts");
  95. try
  96. {
  97. load_fonts(ctx);
  98. }
  99. catch (...)
  100. {
  101. ctx->logger->pop_task(EXIT_FAILURE);
  102. }
  103. ctx->logger->pop_task(EXIT_SUCCESS);
  104. // Create universe
  105. ctx->logger->push_task("Creating the universe");
  106. try
  107. {
  108. cosmogenesis(ctx);
  109. }
  110. catch (...)
  111. {
  112. ctx->logger->pop_task(EXIT_FAILURE);
  113. throw;
  114. }
  115. ctx->logger->pop_task(EXIT_SUCCESS);
  116. // Determine next game state
  117. application::state next_state;
  118. if (ctx->option_quick_start.has_value())
  119. {
  120. next_state.name = "main_menu";
  121. next_state.enter = std::bind(game::state::main_menu::enter, ctx);
  122. next_state.exit = std::bind(game::state::main_menu::exit, ctx);
  123. }
  124. else
  125. {
  126. next_state.name = "splash";
  127. next_state.enter = std::bind(game::state::splash::enter, ctx);
  128. next_state.exit = std::bind(game::state::splash::exit, ctx);
  129. }
  130. // Queue next game state
  131. ctx->app->queue_state(next_state);
  132. }
  133. void exit(game::context* ctx)
  134. {}
  135. void load_controls(game::context* ctx)
  136. {
  137. // If a control profile is set in the config file
  138. if (ctx->config->contains("control_profile"))
  139. {
  140. // Load control profile
  141. json* profile = ctx->resource_manager->load<json>((*ctx->config)["control_profile"].get<std::string>());
  142. // Apply control profile
  143. if (profile)
  144. {
  145. game::apply_control_profile(ctx, *profile);
  146. }
  147. }
  148. // Calibrate gamepads
  149. for (input::gamepad* gamepad: ctx->app->get_gamepads())
  150. {
  151. ctx->logger->push_task("Loading calibration for gamepad " + gamepad->get_guid());
  152. json* calibration = game::load_gamepad_calibration(ctx, gamepad);
  153. if (!calibration)
  154. {
  155. ctx->logger->pop_task(EXIT_FAILURE);
  156. ctx->logger->push_task("Generating default calibration for gamepad " + gamepad->get_guid());
  157. json default_calibration = game::default_gamepad_calibration();
  158. apply_gamepad_calibration(gamepad, default_calibration);
  159. if (!save_gamepad_calibration(ctx, gamepad, default_calibration))
  160. ctx->logger->pop_task(EXIT_FAILURE);
  161. else
  162. ctx->logger->pop_task(EXIT_SUCCESS);
  163. }
  164. else
  165. {
  166. ctx->logger->pop_task(EXIT_SUCCESS);
  167. apply_gamepad_calibration(gamepad, *calibration);
  168. }
  169. }
  170. // Toggle fullscreen
  171. ctx->controls["toggle_fullscreen"]->set_activated_callback
  172. (
  173. [ctx]()
  174. {
  175. bool fullscreen = !ctx->app->is_fullscreen();
  176. ctx->app->set_fullscreen(fullscreen);
  177. if (!fullscreen)
  178. {
  179. int2 resolution;
  180. resolution.x = (*ctx->config)["windowed_resolution"][0].get<int>();
  181. resolution.y = (*ctx->config)["windowed_resolution"][1].get<int>();
  182. ctx->app->resize_window(resolution.x, resolution.y);
  183. }
  184. (*ctx->config)["fullscreen"] = fullscreen;
  185. }
  186. );
  187. // Screenshot
  188. ctx->controls["screenshot"]->set_activated_callback
  189. (
  190. [ctx]()
  191. {
  192. std::string path = ctx->screenshots_path + "antkeeper-" + timestamp() + ".png";
  193. ctx->app->save_frame(path);
  194. }
  195. );
  196. // Menu back
  197. ctx->controls["menu_back"]->set_activated_callback
  198. (
  199. std::bind(&application::close, ctx->app, 0)
  200. );
  201. // Set activation threshold for menu navigation controls to mitigate drifting gamepad axes
  202. const float menu_activation_threshold = 0.1f;
  203. ctx->controls["menu_up"]->set_activation_threshold(menu_activation_threshold);
  204. ctx->controls["menu_down"]->set_activation_threshold(menu_activation_threshold);
  205. ctx->controls["menu_left"]->set_activation_threshold(menu_activation_threshold);
  206. ctx->controls["menu_right"]->set_activation_threshold(menu_activation_threshold);
  207. }
  208. static void build_bitmap_font(const type::typeface& typeface, float size, const std::unordered_set<char32_t>& charset, type::bitmap_font& font, render::material& material, gl::shader_program* shader_program)
  209. {
  210. // Get font metrics for given size
  211. if (type::font_metrics metrics; typeface.get_metrics(size, metrics))
  212. font.set_font_metrics(metrics);
  213. // Format font bitmap
  214. image& font_bitmap = font.get_bitmap();
  215. font_bitmap.format(sizeof(std::byte), 1);
  216. // For each UTF-32 character code in the character set
  217. for (char32_t code: charset)
  218. {
  219. // Skip missing glyphs
  220. if (!typeface.has_glyph(code))
  221. continue;
  222. // Add glyph to font
  223. type::bitmap_glyph& glyph = font[code];
  224. typeface.get_metrics(size, code, glyph.metrics);
  225. typeface.get_bitmap(size, code, glyph.bitmap);
  226. }
  227. // Pack glyph bitmaps into the font bitmap
  228. font.pack();
  229. // Create font texture from bitmap
  230. gl::texture_2d* font_texture = new gl::texture_2d(font_bitmap.get_width(), font_bitmap.get_height(), gl::pixel_type::uint_8, gl::pixel_format::r, gl::color_space::linear, font_bitmap.get_pixels());
  231. font_texture->set_wrapping(gl::texture_wrapping::extend, gl::texture_wrapping::extend);
  232. font_texture->set_filters(gl::texture_min_filter::linear, gl::texture_mag_filter::linear);
  233. // Create font material
  234. material.set_flags(MATERIAL_FLAG_TRANSLUCENT);
  235. material.add_property<const gl::texture_2d*>("font_bitmap")->set_value(font_texture);
  236. material.set_shader_program(shader_program);
  237. }
  238. void load_fonts(game::context* ctx)
  239. {
  240. // Load typefaces
  241. if (auto it = ctx->strings->find("font_serif"); it != ctx->strings->end())
  242. ctx->typefaces["serif"] = ctx->resource_manager->load<type::typeface>(it->second);
  243. if (auto it = ctx->strings->find("font_sans_serif"); it != ctx->strings->end())
  244. ctx->typefaces["sans_serif"] = ctx->resource_manager->load<type::typeface>(it->second);
  245. if (auto it = ctx->strings->find("font_monospace"); it != ctx->strings->end())
  246. ctx->typefaces["monospace"] = ctx->resource_manager->load<type::typeface>(it->second);
  247. // Build character set
  248. std::unordered_set<char32_t> charset;
  249. {
  250. // Add all character codes from the basic Latin unicode block
  251. for (char32_t code = type::unicode::block::basic_latin.first; code <= type::unicode::block::basic_latin.last; ++code)
  252. charset.insert(code);
  253. // Add all character codes from game strings
  254. for (auto it = ctx->strings->begin(); it != ctx->strings->end(); ++it)
  255. {
  256. // Convert UTF-8 string to UTF-32
  257. std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
  258. std::u32string u32 = convert.from_bytes(it->second);
  259. /// Insert each character code from the UTF-32 string into the character set
  260. for (char32_t code: u32)
  261. charset.insert(code);
  262. }
  263. }
  264. // Load bitmap font shader
  265. gl::shader_program* bitmap_font_shader = ctx->resource_manager->load<gl::shader_program>("bitmap-font.glsl");
  266. // Build debug font
  267. if (auto it = ctx->typefaces.find("monospace"); it != ctx->typefaces.end())
  268. {
  269. build_bitmap_font(*it->second, 22.0f, charset, ctx->debug_font, ctx->debug_font_material, bitmap_font_shader);
  270. }
  271. // Build menu font
  272. if (auto it = ctx->typefaces.find("sans_serif"); it != ctx->typefaces.end())
  273. {
  274. build_bitmap_font(*it->second, 28.0f, charset, ctx->menu_font, ctx->menu_font_material, bitmap_font_shader);
  275. }
  276. // Build title font
  277. if (auto it = ctx->typefaces.find("serif"); it != ctx->typefaces.end())
  278. {
  279. build_bitmap_font(*it->second, 96.0f, charset, ctx->title_font, ctx->title_font_material, bitmap_font_shader);
  280. }
  281. }
  282. void cosmogenesis(game::context* ctx)
  283. {
  284. // Init time
  285. const double time = 0.0;
  286. ctx->astronomy_system->set_universal_time(time);
  287. ctx->orbit_system->set_universal_time(time);
  288. // Create sun
  289. ctx->logger->push_task("Creating the sun");
  290. try
  291. {
  292. heliogenesis(ctx);
  293. }
  294. catch (...)
  295. {
  296. ctx->logger->pop_task(EXIT_FAILURE);
  297. throw;
  298. }
  299. ctx->logger->pop_task(EXIT_SUCCESS);
  300. // Create planet
  301. ctx->logger->push_task("Creating the planet");
  302. try
  303. {
  304. planetogenesis(ctx);
  305. }
  306. catch (...)
  307. {
  308. ctx->logger->pop_task(EXIT_FAILURE);
  309. throw;
  310. }
  311. ctx->logger->pop_task(EXIT_SUCCESS);
  312. // Create moon
  313. ctx->logger->push_task("Creating the moon");
  314. try
  315. {
  316. selenogenesis(ctx);
  317. }
  318. catch (...)
  319. {
  320. ctx->logger->pop_task(EXIT_FAILURE);
  321. throw;
  322. }
  323. ctx->logger->pop_task(EXIT_SUCCESS);
  324. // Create fixed stars
  325. ctx->logger->push_task("Creating fixed stars");
  326. try
  327. {
  328. extrasolar_heliogenesis(ctx);
  329. }
  330. catch (...)
  331. {
  332. ctx->logger->pop_task(EXIT_FAILURE);
  333. throw;
  334. }
  335. ctx->logger->pop_task(EXIT_SUCCESS);
  336. // Create ant colony
  337. ctx->logger->push_task("Creating ant colony");
  338. try
  339. {
  340. colonigenesis(ctx);
  341. }
  342. catch (...)
  343. {
  344. ctx->logger->pop_task(EXIT_FAILURE);
  345. throw;
  346. }
  347. ctx->logger->pop_task(EXIT_SUCCESS);
  348. }
  349. void heliogenesis(game::context* ctx)
  350. {
  351. // Create solar entity
  352. entity::archetype* sun_archetype = ctx->resource_manager->load<entity::archetype>("sun.ent");
  353. entity::id sun_eid = sun_archetype->create(*ctx->entity_registry);
  354. ctx->entities["sun"] = sun_eid;
  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::archetype* planet_archetype = ctx->resource_manager->load<entity::archetype>("planet.ent");
  373. entity::id planet_eid = planet_archetype->create(*ctx->entity_registry);
  374. ctx->entities["planet"] = planet_eid;
  375. // Assign planetary terrain component
  376. entity::component::terrain terrain;
  377. terrain.elevation = [](double, double) -> double
  378. {
  379. //return math::random<double>(0.0, 1.0);
  380. return 0.0;
  381. };
  382. terrain.max_lod = 0;
  383. terrain.patch_material = nullptr;
  384. ctx->entity_registry->assign<entity::component::terrain>(planet_eid, terrain);
  385. // Pass planet to astronomy system as reference body
  386. ctx->astronomy_system->set_reference_body(planet_eid);
  387. // Load sky model
  388. ctx->surface_sky_pass->set_sky_model(ctx->resource_manager->load<render::model>("sky-dome.mdl"));
  389. }
  390. void selenogenesis(game::context* ctx)
  391. {
  392. // Create lunar entity
  393. entity::id moon_eid = ctx->entity_registry->create();
  394. ctx->entities["moon"] = moon_eid;
  395. // Pass moon model to sky pass
  396. ctx->surface_sky_pass->set_moon_model(ctx->resource_manager->load<render::model>("moon.mdl"));
  397. }
  398. void extrasolar_heliogenesis(game::context* ctx)
  399. {
  400. // Load star catalog
  401. string_table* star_catalog = ctx->resource_manager->load<string_table>("stars.csv");
  402. // Allocate star catalog vertex data
  403. std::size_t star_count = 0;
  404. if (star_catalog->size() > 0)
  405. star_count = star_catalog->size() - 1;
  406. std::size_t star_vertex_size = 7;
  407. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  408. float* star_vertex_data = new float[star_count * star_vertex_size];
  409. float* star_vertex = star_vertex_data;
  410. // Build star catalog vertex data
  411. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  412. {
  413. const string_table_row& catalog_row = (*star_catalog)[i];
  414. double ra = 0.0;
  415. double dec = 0.0;
  416. double vmag = 0.0;
  417. double bv_color = 0.0;
  418. // Parse star catalog entry
  419. try
  420. {
  421. ra = std::stod(catalog_row[1]);
  422. dec = std::stod(catalog_row[2]);
  423. vmag = std::stod(catalog_row[3]);
  424. bv_color = std::stod(catalog_row[4]);
  425. }
  426. catch (const std::exception& e)
  427. {
  428. continue;
  429. }
  430. // Convert right ascension and declination from degrees to radians
  431. ra = math::wrap_radians(math::radians(ra));
  432. dec = math::wrap_radians(math::radians(dec));
  433. // Transform spherical equatorial coordinates to rectangular equatorial coordinates
  434. double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra});
  435. // Transform coordinates from equatorial space to inertial space
  436. physics::frame<double> bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse();
  437. double3 position_inertial = bci_to_inertial * position_bci;
  438. // Convert color index to color temperature
  439. double cct = color::index::bv_to_cct(bv_color);
  440. // Calculate XYZ color from color temperature
  441. double3 color_xyz = color::cct::to_xyz(cct);
  442. // Transform XYZ color to ACEScg colorspace
  443. double3 color_acescg = color::xyz::to_acescg(color_xyz);
  444. // Convert apparent magnitude to irradiance (W/m^2)
  445. double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4));
  446. // Convert irradiance to illuminance
  447. double vmag_illuminance = vmag_irradiance * (683.0 * 0.14);
  448. // Scale color by illuminance
  449. double3 scaled_color = color_acescg * vmag_illuminance;
  450. // Build vertex
  451. *(star_vertex++) = static_cast<float>(position_inertial.x);
  452. *(star_vertex++) = static_cast<float>(position_inertial.y);
  453. *(star_vertex++) = static_cast<float>(position_inertial.z);
  454. *(star_vertex++) = static_cast<float>(scaled_color.x);
  455. *(star_vertex++) = static_cast<float>(scaled_color.y);
  456. *(star_vertex++) = static_cast<float>(scaled_color.z);
  457. *(star_vertex++) = static_cast<float>(vmag);
  458. }
  459. // Unload star catalog
  460. ctx->resource_manager->unload("stars.csv");
  461. // Allocate stars model
  462. render::model* stars_model = new render::model();
  463. // Get model VBO and VAO
  464. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  465. gl::vertex_array* vao = stars_model->get_vertex_array();
  466. // Resize model VBO and upload vertex data
  467. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  468. // Free star catalog vertex data
  469. delete[] star_vertex_data;
  470. std::size_t attribute_offset = 0;
  471. // Define position vertex attribute
  472. gl::vertex_attribute position_attribute;
  473. position_attribute.buffer = vbo;
  474. position_attribute.offset = attribute_offset;
  475. position_attribute.stride = star_vertex_stride;
  476. position_attribute.type = gl::vertex_attribute_type::float_32;
  477. position_attribute.components = 3;
  478. attribute_offset += position_attribute.components * sizeof(float);
  479. // Define color vertex attribute
  480. gl::vertex_attribute color_attribute;
  481. color_attribute.buffer = vbo;
  482. color_attribute.offset = attribute_offset;
  483. color_attribute.stride = star_vertex_stride;
  484. color_attribute.type = gl::vertex_attribute_type::float_32;
  485. color_attribute.components = 4;
  486. attribute_offset += color_attribute.components * sizeof(float);
  487. // Bind vertex attributes to VAO
  488. vao->bind(render::vertex_attribute::position, position_attribute);
  489. vao->bind(render::vertex_attribute::color, color_attribute);
  490. // Load star material
  491. render::material* star_material = ctx->resource_manager->load<render::material>("fixed-star.mtl");
  492. // Create model group
  493. render::model_group* stars_model_group = stars_model->add_group("stars");
  494. stars_model_group->set_material(star_material);
  495. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  496. stars_model_group->set_start_index(0);
  497. stars_model_group->set_index_count(star_count);
  498. // Pass stars model to sky pass
  499. ctx->surface_sky_pass->set_stars_model(stars_model);
  500. }
  501. void colonigenesis(game::context* ctx)
  502. {}
  503. } // namespace loading
  504. } // namespace state
  505. } // namespace game