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

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