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

626 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 "entity/archetype.hpp"
  33. #include "game/states/nuptial-flight.hpp"
  34. #include "game/states/splash.hpp"
  35. #include "game/states/forage.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 = "forage";
  121. next_state.enter = std::bind(game::state::forage::enter, ctx);
  122. next_state.exit = std::bind(game::state::forage::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. // Create title text
  282. scene::text* title_text = new scene::text();
  283. title_text->set_material(&ctx->title_font_material);
  284. title_text->set_font(&ctx->title_font);
  285. title_text->set_color({1.0f, 1.0f, 1.0f, 1.0f});
  286. title_text->set_content((*ctx->strings)["title"]);
  287. ctx->ui_scene->add_object(title_text);
  288. // Align title text
  289. const auto& title_aabb = static_cast<const geom::aabb<float>&>(title_text->get_local_bounds());
  290. float title_w = title_aabb.max_point.x - title_aabb.min_point.x;
  291. float title_h = title_aabb.max_point.y - title_aabb.min_point.y;
  292. title_text->set_translation({std::round(-title_w * 0.5f), std::round(-title_h * 0.5f), 0.0f});
  293. // Create version string text
  294. scene::text* version_text = new scene::text();
  295. version_text->set_material(&ctx->debug_font_material);
  296. version_text->set_font(&ctx->debug_font);
  297. version_text->set_color({1.0f, 1.0f, 1.0f, 1.0f});
  298. version_text->set_content(ANTKEEPER_VERSION_STRING);
  299. ctx->ui_scene->add_object(version_text);
  300. // Align version string
  301. const auto& version_aabb = static_cast<const geom::aabb<float>&>(version_text->get_local_bounds());
  302. float version_w = version_aabb.max_point.x - version_aabb.min_point.x;
  303. float version_h = version_aabb.max_point.y - version_aabb.min_point.y;
  304. const float version_padding = 12.0f;
  305. auto viewport = ctx->app->get_viewport_dimensions();
  306. version_text->set_translation({viewport[0] * 0.5f - version_w - version_padding, -viewport[1] * 0.5f + version_padding, 0.0f});
  307. }
  308. void cosmogenesis(game::context* ctx)
  309. {
  310. // Init time
  311. const double time = 0.0;
  312. ctx->astronomy_system->set_universal_time(time);
  313. ctx->orbit_system->set_universal_time(time);
  314. // Create sun
  315. ctx->logger->push_task("Creating the sun");
  316. try
  317. {
  318. heliogenesis(ctx);
  319. }
  320. catch (...)
  321. {
  322. ctx->logger->pop_task(EXIT_FAILURE);
  323. throw;
  324. }
  325. ctx->logger->pop_task(EXIT_SUCCESS);
  326. // Create planet
  327. ctx->logger->push_task("Creating the planet");
  328. try
  329. {
  330. planetogenesis(ctx);
  331. }
  332. catch (...)
  333. {
  334. ctx->logger->pop_task(EXIT_FAILURE);
  335. throw;
  336. }
  337. ctx->logger->pop_task(EXIT_SUCCESS);
  338. // Create moon
  339. ctx->logger->push_task("Creating the moon");
  340. try
  341. {
  342. selenogenesis(ctx);
  343. }
  344. catch (...)
  345. {
  346. ctx->logger->pop_task(EXIT_FAILURE);
  347. throw;
  348. }
  349. ctx->logger->pop_task(EXIT_SUCCESS);
  350. // Create fixed stars
  351. ctx->logger->push_task("Creating fixed stars");
  352. try
  353. {
  354. extrasolar_heliogenesis(ctx);
  355. }
  356. catch (...)
  357. {
  358. ctx->logger->pop_task(EXIT_FAILURE);
  359. throw;
  360. }
  361. ctx->logger->pop_task(EXIT_SUCCESS);
  362. // Create ant colony
  363. ctx->logger->push_task("Creating ant colony");
  364. try
  365. {
  366. colonigenesis(ctx);
  367. }
  368. catch (...)
  369. {
  370. ctx->logger->pop_task(EXIT_FAILURE);
  371. throw;
  372. }
  373. ctx->logger->pop_task(EXIT_SUCCESS);
  374. }
  375. void heliogenesis(game::context* ctx)
  376. {
  377. // Create solar entity
  378. entity::archetype* sun_archetype = ctx->resource_manager->load<entity::archetype>("sun.ent");
  379. entity::id sun_eid = sun_archetype->create(*ctx->entity_registry);
  380. ctx->entities["sun"] = sun_eid;
  381. // Create direct sun light scene object
  382. scene::directional_light* sun_direct = new scene::directional_light();
  383. // Create ambient sun light scene object
  384. scene::ambient_light* sun_ambient = new scene::ambient_light();
  385. sun_ambient->set_color({1, 1, 1});
  386. sun_ambient->set_intensity(0.0f);
  387. sun_ambient->update_tweens();
  388. // Add sun light scene objects to surface scene
  389. ctx->surface_scene->add_object(sun_direct);
  390. ctx->surface_scene->add_object(sun_ambient);
  391. // Pass direct sun light scene object to shadow map pass and astronomy system
  392. ctx->surface_shadow_map_pass->set_light(sun_direct);
  393. ctx->astronomy_system->set_sun_light(sun_direct);
  394. }
  395. void planetogenesis(game::context* ctx)
  396. {
  397. // Create planetary entity
  398. entity::archetype* planet_archetype = ctx->resource_manager->load<entity::archetype>("planet.ent");
  399. entity::id planet_eid = planet_archetype->create(*ctx->entity_registry);
  400. ctx->entities["planet"] = planet_eid;
  401. // Assign planetary terrain component
  402. entity::component::terrain terrain;
  403. terrain.elevation = [](double, double) -> double
  404. {
  405. //return math::random<double>(0.0, 1.0);
  406. return 0.0;
  407. };
  408. terrain.max_lod = 0;
  409. terrain.patch_material = nullptr;
  410. ctx->entity_registry->assign<entity::component::terrain>(planet_eid, terrain);
  411. // Pass planet to astronomy system as reference body
  412. ctx->astronomy_system->set_reference_body(planet_eid);
  413. // Load sky model
  414. ctx->surface_sky_pass->set_sky_model(ctx->resource_manager->load<render::model>("sky-dome.mdl"));
  415. }
  416. void selenogenesis(game::context* ctx)
  417. {
  418. // Create lunar entity
  419. entity::id moon_eid = ctx->entity_registry->create();
  420. ctx->entities["moon"] = moon_eid;
  421. // Pass moon model to sky pass
  422. ctx->surface_sky_pass->set_moon_model(ctx->resource_manager->load<render::model>("moon.mdl"));
  423. }
  424. void extrasolar_heliogenesis(game::context* ctx)
  425. {
  426. // Load star catalog
  427. string_table* star_catalog = ctx->resource_manager->load<string_table>("stars.csv");
  428. // Allocate star catalog vertex data
  429. std::size_t star_count = 0;
  430. if (star_catalog->size() > 0)
  431. star_count = star_catalog->size() - 1;
  432. std::size_t star_vertex_size = 7;
  433. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  434. float* star_vertex_data = new float[star_count * star_vertex_size];
  435. float* star_vertex = star_vertex_data;
  436. // Build star catalog vertex data
  437. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  438. {
  439. const string_table_row& catalog_row = (*star_catalog)[i];
  440. double ra = 0.0;
  441. double dec = 0.0;
  442. double vmag = 0.0;
  443. double bv_color = 0.0;
  444. // Parse star catalog entry
  445. try
  446. {
  447. ra = std::stod(catalog_row[1]);
  448. dec = std::stod(catalog_row[2]);
  449. vmag = std::stod(catalog_row[3]);
  450. bv_color = std::stod(catalog_row[4]);
  451. }
  452. catch (const std::exception& e)
  453. {
  454. continue;
  455. }
  456. // Convert right ascension and declination from degrees to radians
  457. ra = math::wrap_radians(math::radians(ra));
  458. dec = math::wrap_radians(math::radians(dec));
  459. // Transform spherical equatorial coordinates to rectangular equatorial coordinates
  460. double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra});
  461. // Transform coordinates from equatorial space to inertial space
  462. physics::frame<double> bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse();
  463. double3 position_inertial = bci_to_inertial * position_bci;
  464. // Convert color index to color temperature
  465. double cct = color::index::bv_to_cct(bv_color);
  466. // Calculate XYZ color from color temperature
  467. double3 color_xyz = color::cct::to_xyz(cct);
  468. // Transform XYZ color to ACEScg colorspace
  469. double3 color_acescg = color::xyz::to_acescg(color_xyz);
  470. // Convert apparent magnitude to irradiance (W/m^2)
  471. double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4));
  472. // Convert irradiance to illuminance
  473. double vmag_illuminance = vmag_irradiance * (683.0 * 0.14);
  474. // Scale color by illuminance
  475. double3 scaled_color = color_acescg * vmag_illuminance;
  476. // Build vertex
  477. *(star_vertex++) = static_cast<float>(position_inertial.x);
  478. *(star_vertex++) = static_cast<float>(position_inertial.y);
  479. *(star_vertex++) = static_cast<float>(position_inertial.z);
  480. *(star_vertex++) = static_cast<float>(scaled_color.x);
  481. *(star_vertex++) = static_cast<float>(scaled_color.y);
  482. *(star_vertex++) = static_cast<float>(scaled_color.z);
  483. *(star_vertex++) = static_cast<float>(vmag);
  484. }
  485. // Unload star catalog
  486. ctx->resource_manager->unload("stars.csv");
  487. // Allocate stars model
  488. render::model* stars_model = new render::model();
  489. // Get model VBO and VAO
  490. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  491. gl::vertex_array* vao = stars_model->get_vertex_array();
  492. // Resize model VBO and upload vertex data
  493. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  494. // Free star catalog vertex data
  495. delete[] star_vertex_data;
  496. std::size_t attribute_offset = 0;
  497. // Define position vertex attribute
  498. gl::vertex_attribute position_attribute;
  499. position_attribute.buffer = vbo;
  500. position_attribute.offset = attribute_offset;
  501. position_attribute.stride = star_vertex_stride;
  502. position_attribute.type = gl::vertex_attribute_type::float_32;
  503. position_attribute.components = 3;
  504. attribute_offset += position_attribute.components * sizeof(float);
  505. // Define color vertex attribute
  506. gl::vertex_attribute color_attribute;
  507. color_attribute.buffer = vbo;
  508. color_attribute.offset = attribute_offset;
  509. color_attribute.stride = star_vertex_stride;
  510. color_attribute.type = gl::vertex_attribute_type::float_32;
  511. color_attribute.components = 4;
  512. attribute_offset += color_attribute.components * sizeof(float);
  513. // Bind vertex attributes to VAO
  514. vao->bind(render::vertex_attribute::position, position_attribute);
  515. vao->bind(render::vertex_attribute::color, color_attribute);
  516. // Load star material
  517. render::material* star_material = ctx->resource_manager->load<render::material>("fixed-star.mtl");
  518. // Create model group
  519. render::model_group* stars_model_group = stars_model->add_group("stars");
  520. stars_model_group->set_material(star_material);
  521. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  522. stars_model_group->set_start_index(0);
  523. stars_model_group->set_index_count(star_count);
  524. // Pass stars model to sky pass
  525. ctx->surface_sky_pass->set_stars_model(stars_model);
  526. }
  527. void colonigenesis(game::context* ctx)
  528. {}
  529. } // namespace loading
  530. } // namespace state
  531. } // namespace game