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

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