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

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