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

830 lines
30 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 "game/states/nuptial-flight.hpp"
  33. #include "game/states/splash.hpp"
  34. #include "game/states/forage.hpp"
  35. #include "geom/spherical.hpp"
  36. #include "gl/drawing-mode.hpp"
  37. #include "gl/vertex-array.hpp"
  38. #include "gl/vertex-attribute-type.hpp"
  39. #include "gl/vertex-buffer.hpp"
  40. #include "physics/light/photometry.hpp"
  41. #include "physics/orbit/orbit.hpp"
  42. #include "renderer/material.hpp"
  43. #include "renderer/model.hpp"
  44. #include "renderer/passes/shadow-map-pass.hpp"
  45. #include "renderer/vertex-attributes.hpp"
  46. #include "resources/resource-manager.hpp"
  47. #include "scene/ambient-light.hpp"
  48. #include "scene/directional-light.hpp"
  49. #include "utility/timestamp.hpp"
  50. namespace game {
  51. namespace state {
  52. namespace loading {
  53. /// Creates or loads control configuration
  54. static void load_controls(game::context* ctx);
  55. static input::gamepad_response_curve parse_response_curve(const std::string& curve);
  56. /// Creates the universe and solar system.
  57. static void cosmogenesis(game::context* ctx);
  58. /// Creates a sun.
  59. static void heliogenesis(game::context* ctx);
  60. /// Creates a planet.
  61. static void planetogenesis(game::context* ctx);
  62. /// Creates a moon.
  63. static void selenogenesis(game::context* ctx);
  64. /// Creates fixed stars.
  65. static void extrasolar_heliogenesis(game::context* ctx);
  66. /// Creates an ant colony
  67. static void colonigenesis(game::context* ctx);
  68. void enter(game::context* ctx)
  69. {
  70. // Load controls
  71. ctx->logger->push_task("Loading controls");
  72. try
  73. {
  74. load_controls(ctx);
  75. }
  76. catch (...)
  77. {
  78. ctx->logger->pop_task(EXIT_FAILURE);
  79. }
  80. ctx->logger->pop_task(EXIT_SUCCESS);
  81. // Create universe
  82. ctx->logger->push_task("Creating the universe");
  83. try
  84. {
  85. cosmogenesis(ctx);
  86. }
  87. catch (...)
  88. {
  89. ctx->logger->pop_task(EXIT_FAILURE);
  90. throw;
  91. }
  92. ctx->logger->pop_task(EXIT_SUCCESS);
  93. // Determine next game state
  94. application::state next_state;
  95. if (ctx->option_quick_start.has_value())
  96. {
  97. next_state.name = "forage";
  98. next_state.enter = std::bind(game::state::forage::enter, ctx);
  99. next_state.exit = std::bind(game::state::forage::exit, ctx);
  100. }
  101. else
  102. {
  103. next_state.name = "splash";
  104. next_state.enter = std::bind(game::state::splash::enter, ctx);
  105. next_state.exit = std::bind(game::state::splash::exit, ctx);
  106. }
  107. // Queue next game state
  108. ctx->app->queue_state(next_state);
  109. }
  110. void exit(game::context* ctx)
  111. {}
  112. void load_controls(game::context* ctx)
  113. {
  114. // Allocate known controls
  115. ctx->controls["toggle_fullscreen"] = new input::control();
  116. ctx->controls["screenshot"] = new input::control();
  117. ctx->controls["menu_up"] = new input::control();
  118. ctx->controls["menu_down"] = new input::control();
  119. ctx->controls["menu_left"] = new input::control();
  120. ctx->controls["menu_right"] = new input::control();
  121. ctx->controls["menu_select"] = new input::control();
  122. ctx->controls["menu_back"] = new input::control();
  123. ctx->controls["dolly_forward"] = new input::control();
  124. ctx->controls["dolly_backward"] = new input::control();
  125. ctx->controls["truck_left"] = new input::control();
  126. ctx->controls["truck_right"] = new input::control();
  127. ctx->controls["pedestal_up"] = new input::control();
  128. ctx->controls["pedestal_down"] = new input::control();
  129. ctx->controls["move_slow"] = new input::control();
  130. ctx->controls["move_fast"] = new input::control();
  131. ctx->controls["mouse_rotate"] = new input::control();
  132. ctx->controls["pan_left_gamepad"] = new input::control();
  133. ctx->controls["pan_left_mouse"] = new input::control();
  134. ctx->controls["pan_right_gamepad"] = new input::control();
  135. ctx->controls["pan_right_mouse"] = new input::control();
  136. ctx->controls["tilt_up_gamepad"] = new input::control();
  137. ctx->controls["tilt_up_mouse"] = new input::control();
  138. ctx->controls["tilt_down_gamepad"] = new input::control();
  139. ctx->controls["tilt_down_mouse"] = new input::control();
  140. ctx->controls["use_tool"] = new input::control();
  141. // Set activation threshold for menu navigation controls to mitigate drifting gamepad axes
  142. const float menu_activation_threshold = 0.1f;
  143. ctx->controls["menu_up"]->set_activation_threshold(menu_activation_threshold);
  144. ctx->controls["menu_down"]->set_activation_threshold(menu_activation_threshold);
  145. ctx->controls["menu_left"]->set_activation_threshold(menu_activation_threshold);
  146. ctx->controls["menu_right"]->set_activation_threshold(menu_activation_threshold);
  147. // Get keyboard and mouse devices
  148. input::keyboard* keyboard = ctx->app->get_keyboard();
  149. input::mouse* mouse = ctx->app->get_mouse();
  150. const std::unordered_map<std::string, input::gamepad_button> gamepad_button_map =
  151. {
  152. {"a", input::gamepad_button::a},
  153. {"b", input::gamepad_button::b},
  154. {"x", input::gamepad_button::x},
  155. {"y", input::gamepad_button::y},
  156. {"back", input::gamepad_button::back},
  157. {"guide", input::gamepad_button::guide},
  158. {"start", input::gamepad_button::start},
  159. {"leftstick", input::gamepad_button::left_stick},
  160. {"rightstick", input::gamepad_button::right_stick},
  161. {"leftshoulder", input::gamepad_button::left_shoulder},
  162. {"rightshoulder", input::gamepad_button::right_shoulder},
  163. {"dpup", input::gamepad_button::dpad_up},
  164. {"dpdown", input::gamepad_button::dpad_down},
  165. {"dpleft", input::gamepad_button::dpad_left},
  166. {"dpright", input::gamepad_button::dpad_right}
  167. };
  168. const std::unordered_map<std::string, input::gamepad_axis> gamepad_axis_map =
  169. {
  170. {"leftx", input::gamepad_axis::left_x},
  171. {"lefty", input::gamepad_axis::left_y},
  172. {"rightx", input::gamepad_axis::right_x},
  173. {"righty", input::gamepad_axis::right_y},
  174. {"lefttrigger", input::gamepad_axis::left_trigger},
  175. {"righttrigger", input::gamepad_axis::right_trigger}
  176. };
  177. // Check if a control profile is set in the config file
  178. if (ctx->config->contains("control_profile"))
  179. {
  180. // Load control profile
  181. json* profile = ctx->resource_manager->load<json>((*ctx->config)["control_profile"].get<std::string>());
  182. // Parse control profile
  183. for (auto it = profile->begin(); it != profile->end(); ++it)
  184. {
  185. // Parse control name
  186. if (!it->contains("name"))
  187. {
  188. ctx->logger->warning("Unnamed control in control profile");
  189. continue;
  190. }
  191. std::string name = (*it)["name"].get<std::string>();
  192. // Find or create control
  193. input::control* control;
  194. if (ctx->controls.count(name))
  195. {
  196. control = ctx->controls[name];
  197. }
  198. else
  199. {
  200. control = new input::control;
  201. ctx->controls[name] = control;
  202. }
  203. // Parse control device
  204. if (!it->contains("device"))
  205. {
  206. ctx->logger->warning("Control \"" + name + "\" not mapped to a device");
  207. continue;
  208. }
  209. std::string device = (*it)["device"].get<std::string>();
  210. if (device == "keyboard")
  211. {
  212. // Parse key name
  213. if (!it->contains("key"))
  214. {
  215. ctx->logger->warning("Control \"" + name + "\" has invalid keyboard mapping");
  216. continue;
  217. }
  218. std::string key = (*it)["key"].get<std::string>();
  219. // Get scancode from key name
  220. input::scancode scancode = keyboard->get_scancode_from_name(key.c_str());
  221. if (scancode == input::scancode::unknown)
  222. {
  223. ctx->logger->warning("Control \"" + name + "\" mapped to unknown keyboard key \"" + key + "\"");
  224. continue;
  225. }
  226. // Map control to keyboard key
  227. ctx->input_event_router->add_mapping(input::key_mapping(control, nullptr, scancode));
  228. ctx->logger->log("Mapped control \"" + name + "\" to keyboard key \"" + key + "\"");
  229. }
  230. else if (device == "mouse")
  231. {
  232. if (it->contains("button"))
  233. {
  234. // Parse mouse button index
  235. int button = (*it)["button"].get<int>();
  236. // Map control to mouse button
  237. ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, nullptr, button));
  238. ctx->logger->log("Mapped control \"" + name + "\" to mouse button " + std::to_string(button));
  239. }
  240. else if (it->contains("wheel"))
  241. {
  242. // Parse mouse wheel axis
  243. std::string wheel = (*it)["wheel"].get<std::string>();
  244. input::mouse_wheel_axis axis;
  245. if (wheel == "x+")
  246. axis = input::mouse_wheel_axis::positive_x;
  247. else if (wheel == "x-")
  248. axis = input::mouse_wheel_axis::negative_x;
  249. else if (wheel == "y+")
  250. axis = input::mouse_wheel_axis::positive_y;
  251. else if (wheel == "y-")
  252. axis = input::mouse_wheel_axis::negative_y;
  253. else
  254. {
  255. ctx->logger->warning("Control \"" + name + "\" is mapped to invalid mouse wheel axis \"" + wheel + "\"");
  256. continue;
  257. }
  258. // Map control to mouse wheel axis
  259. ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, nullptr, axis));
  260. ctx->logger->log("Mapped control \"" + name + "\" to mouse wheel axis " + wheel);
  261. }
  262. else if (it->contains("motion"))
  263. {
  264. std::string motion = (*it)["motion"].get<std::string>();
  265. input::mouse_motion_axis axis;
  266. if (motion == "x+")
  267. axis = input::mouse_motion_axis::positive_x;
  268. else if (motion == "x-")
  269. axis = input::mouse_motion_axis::negative_x;
  270. else if (motion == "y+")
  271. axis = input::mouse_motion_axis::positive_y;
  272. else if (motion == "y-")
  273. axis = input::mouse_motion_axis::negative_y;
  274. else
  275. {
  276. ctx->logger->warning("Control \"" + name + "\" is mapped to invalid mouse motion axis \"" + motion + "\"");
  277. continue;
  278. }
  279. // Map control to mouse motion axis
  280. ctx->input_event_router->add_mapping(input::mouse_motion_mapping(control, nullptr, axis));
  281. ctx->logger->log("Mapped control \"" + name + "\" to mouse motion axis " + motion);
  282. }
  283. else
  284. {
  285. ctx->logger->warning("Control \"" + name + "\" has invalid mouse mapping");
  286. continue;
  287. }
  288. }
  289. else if (device == "gamepad")
  290. {
  291. if (it->contains("button"))
  292. {
  293. // Parse gamepad button
  294. std::string button = (*it)["button"].get<std::string>();
  295. auto button_it = gamepad_button_map.find(button);
  296. if (button_it == gamepad_button_map.end())
  297. {
  298. ctx->logger->warning("Control \"" + name + "\" is mapped to invalid gamepad button \"" + button + "\"");
  299. continue;
  300. }
  301. // Map control to gamepad button
  302. ctx->input_event_router->add_mapping(input::gamepad_button_mapping(control, nullptr, button_it->second));
  303. ctx->logger->log("Mapped control \"" + name + "\" to gamepad button " + button);
  304. }
  305. else if (it->contains("axis"))
  306. {
  307. std::string axis = (*it)["axis"].get<std::string>();
  308. // Parse gamepad axis name
  309. const std::string axis_name = axis.substr(0, axis.length() - 1);
  310. auto axis_it = gamepad_axis_map.find(axis_name);
  311. if (axis_it == gamepad_axis_map.end())
  312. {
  313. ctx->logger->warning("Control \"" + name + "\" is mapped to invalid gamepad axis \"" + axis_name + "\"");
  314. continue;
  315. }
  316. // Parse gamepad axis sign
  317. const char axis_sign = axis.back();
  318. if (axis_sign != '-' && axis_sign != '+')
  319. {
  320. ctx->logger->warning("Control \"" + name + "\" is mapped to gamepad axis with invalid sign \"" + axis_sign + "\"");
  321. continue;
  322. }
  323. bool axis_negative = (axis_sign == '-');
  324. // Map control to gamepad axis
  325. ctx->input_event_router->add_mapping(input::gamepad_axis_mapping(control, nullptr, axis_it->second, axis_negative));
  326. ctx->logger->log("Mapped control \"" + name + "\" to gamepad axis " + axis);
  327. }
  328. else
  329. {
  330. ctx->logger->log("Control \"" + name + "\" has invalid gamepad mapping");
  331. continue;
  332. }
  333. }
  334. else
  335. {
  336. ctx->logger->warning("Control \"" + name + "\" bound to unknown device \"" + device + "\"");
  337. }
  338. }
  339. }
  340. // Set gamepad deadzones
  341. float gamepad_leftx_activation_min = 0.0f;
  342. float gamepad_leftx_activation_max = 0.0f;
  343. float gamepad_lefty_activation_min = 0.0f;
  344. float gamepad_lefty_activation_max = 0.0f;
  345. float gamepad_rightx_activation_min = 0.0f;
  346. float gamepad_rightx_activation_max = 0.0f;
  347. float gamepad_righty_activation_min = 0.0f;
  348. float gamepad_righty_activation_max = 0.0f;
  349. float gamepad_lefttrigger_activation_min = 0.0f;
  350. float gamepad_lefttrigger_activation_max = 0.0f;
  351. float gamepad_righttrigger_activation_min = 0.0f;
  352. float gamepad_righttrigger_activation_max = 0.0f;
  353. bool gamepad_left_deadzone_cross = true;
  354. bool gamepad_right_deadzone_cross = true;
  355. float gamepad_left_deadzone_roundness = 0.0f;
  356. float gamepad_right_deadzone_roundness = 0.0f;
  357. input::gamepad_response_curve gamepad_leftx_response_curve = input::gamepad_response_curve::linear;
  358. input::gamepad_response_curve gamepad_lefty_response_curve = input::gamepad_response_curve::linear;
  359. input::gamepad_response_curve gamepad_rightx_response_curve = input::gamepad_response_curve::linear;
  360. input::gamepad_response_curve gamepad_righty_response_curve = input::gamepad_response_curve::linear;
  361. input::gamepad_response_curve gamepad_lefttrigger_response_curve = input::gamepad_response_curve::linear;
  362. input::gamepad_response_curve gamepad_righttrigger_response_curve = input::gamepad_response_curve::linear;
  363. if (ctx->config->contains("gamepad_leftx_activation_min"))
  364. gamepad_leftx_activation_min = (*ctx->config)["gamepad_leftx_activation_min"].get<float>();
  365. if (ctx->config->contains("gamepad_leftx_activation_max"))
  366. gamepad_leftx_activation_max = (*ctx->config)["gamepad_leftx_activation_max"].get<float>();
  367. if (ctx->config->contains("gamepad_lefty_activation_min"))
  368. gamepad_lefty_activation_min = (*ctx->config)["gamepad_lefty_activation_min"].get<float>();
  369. if (ctx->config->contains("gamepad_lefty_activation_max"))
  370. gamepad_lefty_activation_max = (*ctx->config)["gamepad_lefty_activation_max"].get<float>();
  371. if (ctx->config->contains("gamepad_rightx_activation_min"))
  372. gamepad_rightx_activation_min = (*ctx->config)["gamepad_rightx_activation_min"].get<float>();
  373. if (ctx->config->contains("gamepad_rightx_activation_max"))
  374. gamepad_rightx_activation_max = (*ctx->config)["gamepad_rightx_activation_max"].get<float>();
  375. if (ctx->config->contains("gamepad_righty_activation_min"))
  376. gamepad_righty_activation_min = (*ctx->config)["gamepad_righty_activation_min"].get<float>();
  377. if (ctx->config->contains("gamepad_righty_activation_max"))
  378. gamepad_righty_activation_max = (*ctx->config)["gamepad_righty_activation_max"].get<float>();
  379. if (ctx->config->contains("gamepad_lefttrigger_activation_min"))
  380. gamepad_lefttrigger_activation_min = (*ctx->config)["gamepad_lefttrigger_activation_min"].get<float>();
  381. if (ctx->config->contains("gamepad_lefttrigger_activation_max"))
  382. gamepad_lefttrigger_activation_max = (*ctx->config)["gamepad_lefttrigger_activation_max"].get<float>();
  383. if (ctx->config->contains("gamepad_righttrigger_activation_min"))
  384. gamepad_righttrigger_activation_min = (*ctx->config)["gamepad_righttrigger_activation_min"].get<float>();
  385. if (ctx->config->contains("gamepad_righttrigger_activation_max"))
  386. gamepad_righttrigger_activation_max = (*ctx->config)["gamepad_righttrigger_activation_max"].get<float>();
  387. if (ctx->config->contains("gamepad_left_deadzone_cross"))
  388. gamepad_left_deadzone_cross = (*ctx->config)["gamepad_left_deadzone_cross"].get<bool>();
  389. if (ctx->config->contains("gamepad_right_deadzone_cross"))
  390. gamepad_right_deadzone_cross = (*ctx->config)["gamepad_right_deadzone_cross"].get<bool>();
  391. if (ctx->config->contains("gamepad_left_deadzone_roundness"))
  392. gamepad_left_deadzone_roundness = (*ctx->config)["gamepad_left_deadzone_roundness"].get<float>();
  393. if (ctx->config->contains("gamepad_right_deadzone_roundness"))
  394. gamepad_right_deadzone_roundness = (*ctx->config)["gamepad_right_deadzone_roundness"].get<float>();
  395. if (ctx->config->contains("gamepad_leftx_response_curve"))
  396. gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get<std::string>());
  397. if (ctx->config->contains("gamepad_leftx_response_curve"))
  398. gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get<std::string>());
  399. if (ctx->config->contains("gamepad_rightx_response_curve"))
  400. gamepad_rightx_response_curve = parse_response_curve((*ctx->config)["gamepad_rightx_response_curve"].get<std::string>());
  401. if (ctx->config->contains("gamepad_leftx_response_curve"))
  402. gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get<std::string>());
  403. if (ctx->config->contains("gamepad_lefttrigger_response_curve"))
  404. gamepad_lefttrigger_response_curve = parse_response_curve((*ctx->config)["gamepad_lefttrigger_response_curve"].get<std::string>());
  405. if (ctx->config->contains("gamepad_righttrigger_response_curve"))
  406. gamepad_righttrigger_response_curve = parse_response_curve((*ctx->config)["gamepad_righttrigger_response_curve"].get<std::string>());
  407. for (input::gamepad* gamepad: ctx->app->get_gamepads())
  408. {
  409. gamepad->set_activation_threshold(input::gamepad_axis::left_x, gamepad_leftx_activation_min, gamepad_leftx_activation_max);
  410. gamepad->set_activation_threshold(input::gamepad_axis::left_y, gamepad_lefty_activation_min, gamepad_lefty_activation_max);
  411. gamepad->set_activation_threshold(input::gamepad_axis::right_x, gamepad_rightx_activation_min, gamepad_rightx_activation_max);
  412. gamepad->set_activation_threshold(input::gamepad_axis::right_y, gamepad_righty_activation_min, gamepad_righty_activation_max);
  413. gamepad->set_activation_threshold(input::gamepad_axis::left_trigger, gamepad_lefttrigger_activation_min, gamepad_lefttrigger_activation_max);
  414. gamepad->set_activation_threshold(input::gamepad_axis::right_trigger, gamepad_righttrigger_activation_min, gamepad_righttrigger_activation_max);
  415. gamepad->set_left_deadzone_cross(gamepad_left_deadzone_cross);
  416. gamepad->set_right_deadzone_cross(gamepad_right_deadzone_cross);
  417. gamepad->set_left_deadzone_roundness(gamepad_left_deadzone_roundness);
  418. gamepad->set_right_deadzone_roundness(gamepad_right_deadzone_roundness);
  419. gamepad->set_response_curve(input::gamepad_axis::left_x, gamepad_leftx_response_curve);
  420. gamepad->set_response_curve(input::gamepad_axis::left_y, gamepad_lefty_response_curve);
  421. gamepad->set_response_curve(input::gamepad_axis::right_x, gamepad_rightx_response_curve);
  422. gamepad->set_response_curve(input::gamepad_axis::right_y, gamepad_righty_response_curve);
  423. gamepad->set_response_curve(input::gamepad_axis::left_trigger, gamepad_lefttrigger_response_curve);
  424. gamepad->set_response_curve(input::gamepad_axis::right_trigger, gamepad_righttrigger_response_curve);
  425. }
  426. // Toggle fullscreen
  427. ctx->controls["toggle_fullscreen"]->set_activated_callback
  428. (
  429. [ctx]()
  430. {
  431. bool fullscreen = !ctx->app->is_fullscreen();
  432. ctx->app->set_fullscreen(fullscreen);
  433. if (!fullscreen)
  434. {
  435. int2 resolution;
  436. resolution.x = (*ctx->config)["windowed_resolution"][0].get<int>();
  437. resolution.y = (*ctx->config)["windowed_resolution"][1].get<int>();
  438. ctx->app->resize_window(resolution.x, resolution.y);
  439. }
  440. (*ctx->config)["fullscreen"] = fullscreen;
  441. }
  442. );
  443. // Screenshot
  444. ctx->controls["screenshot"]->set_activated_callback
  445. (
  446. [ctx]()
  447. {
  448. std::string path = ctx->screenshots_path + "antkeeper-" + timestamp() + ".png";
  449. ctx->app->save_frame(path);
  450. }
  451. );
  452. // Menu back
  453. ctx->controls["menu_back"]->set_activated_callback
  454. (
  455. std::bind(&application::close, ctx->app, 0)
  456. );
  457. }
  458. static input::gamepad_response_curve parse_response_curve(const std::string& curve)
  459. {
  460. if (curve == "square")
  461. return input::gamepad_response_curve::square;
  462. else if (curve == "cube")
  463. return input::gamepad_response_curve::cube;
  464. return input::gamepad_response_curve::linear;
  465. }
  466. void cosmogenesis(game::context* ctx)
  467. {
  468. // Init time
  469. const double time = 0.0;
  470. ctx->astronomy_system->set_universal_time(time);
  471. ctx->orbit_system->set_universal_time(time);
  472. // Create sun
  473. ctx->logger->push_task("Creating the sun");
  474. try
  475. {
  476. heliogenesis(ctx);
  477. }
  478. catch (...)
  479. {
  480. ctx->logger->pop_task(EXIT_FAILURE);
  481. throw;
  482. }
  483. ctx->logger->pop_task(EXIT_SUCCESS);
  484. // Create planet
  485. ctx->logger->push_task("Creating the planet");
  486. try
  487. {
  488. planetogenesis(ctx);
  489. }
  490. catch (...)
  491. {
  492. ctx->logger->pop_task(EXIT_FAILURE);
  493. throw;
  494. }
  495. ctx->logger->pop_task(EXIT_SUCCESS);
  496. // Create moon
  497. ctx->logger->push_task("Creating the moon");
  498. try
  499. {
  500. selenogenesis(ctx);
  501. }
  502. catch (...)
  503. {
  504. ctx->logger->pop_task(EXIT_FAILURE);
  505. throw;
  506. }
  507. ctx->logger->pop_task(EXIT_SUCCESS);
  508. // Create fixed stars
  509. ctx->logger->push_task("Creating fixed stars");
  510. try
  511. {
  512. extrasolar_heliogenesis(ctx);
  513. }
  514. catch (...)
  515. {
  516. ctx->logger->pop_task(EXIT_FAILURE);
  517. throw;
  518. }
  519. ctx->logger->pop_task(EXIT_SUCCESS);
  520. // Create ant colony
  521. ctx->logger->push_task("Creating ant colony");
  522. try
  523. {
  524. colonigenesis(ctx);
  525. }
  526. catch (...)
  527. {
  528. ctx->logger->pop_task(EXIT_FAILURE);
  529. throw;
  530. }
  531. ctx->logger->pop_task(EXIT_SUCCESS);
  532. }
  533. void heliogenesis(game::context* ctx)
  534. {
  535. // Create solar entity
  536. entity::id sun_eid = ctx->entity_registry->create();
  537. ctx->entities["sun"] = sun_eid;
  538. // Assign solar celestial body component
  539. entity::component::celestial_body body;
  540. body.radius = 6.957e+8;
  541. body.axial_tilt = math::radians(0.0);
  542. body.axial_rotation = math::radians(0.0);
  543. body.angular_frequency = math::radians(0.0);
  544. ctx->entity_registry->assign<entity::component::celestial_body>(sun_eid, body);
  545. // Assign solar orbit component
  546. entity::component::orbit orbit;
  547. orbit.elements.a = 0.0;
  548. orbit.elements.e = 0.0;
  549. orbit.elements.i = math::radians(0.0);
  550. orbit.elements.raan = math::radians(0.0);
  551. orbit.elements.w = math::radians(0.0);
  552. orbit.elements.ta = math::radians(0.0);
  553. ctx->entity_registry->assign<entity::component::orbit>(sun_eid, orbit);
  554. // Assign solar blackbody component
  555. entity::component::blackbody blackbody;
  556. blackbody.temperature = 5778.0;
  557. ctx->entity_registry->assign<entity::component::blackbody>(sun_eid, blackbody);
  558. // Assign solar transform component
  559. entity::component::transform transform;
  560. transform.local = math::identity_transform<float>;
  561. transform.warp = true;
  562. ctx->entity_registry->assign<entity::component::transform>(sun_eid, transform);
  563. // Create direct sun light scene object
  564. scene::directional_light* sun_direct = new scene::directional_light();
  565. // Create ambient sun light scene object
  566. scene::ambient_light* sun_ambient = new scene::ambient_light();
  567. sun_ambient->set_color({1, 1, 1});
  568. sun_ambient->set_intensity(0.0f);
  569. sun_ambient->update_tweens();
  570. // Add sun light scene objects to surface scene
  571. ctx->surface_scene->add_object(sun_direct);
  572. ctx->surface_scene->add_object(sun_ambient);
  573. // Pass direct sun light scene object to shadow map pass and astronomy system
  574. ctx->surface_shadow_map_pass->set_light(sun_direct);
  575. ctx->astronomy_system->set_sun_light(sun_direct);
  576. }
  577. void planetogenesis(game::context* ctx)
  578. {
  579. // Create planetary entity
  580. entity::id planet_eid = ctx->entity_registry->create();
  581. ctx->entities["planet"] = planet_eid;
  582. // Assign planetary celestial body component
  583. entity::component::celestial_body body;
  584. body.radius = 6.3781e6;
  585. body.axial_tilt = math::radians(23.4393);
  586. body.axial_rotation = math::radians(280.46061837504);
  587. body.angular_frequency = math::radians(360.9856122880876128);
  588. ctx->entity_registry->assign<entity::component::celestial_body>(planet_eid, body);
  589. // Assign planetary orbit component
  590. entity::component::orbit orbit;
  591. orbit.elements.a = 1.496e+11;
  592. orbit.elements.e = 0.01671123;
  593. orbit.elements.i = math::radians(-0.00001531);
  594. orbit.elements.raan = math::radians(0.0);
  595. const double longitude_periapsis = math::radians(102.93768193);
  596. orbit.elements.w = longitude_periapsis - orbit.elements.raan;
  597. orbit.elements.ta = math::radians(100.46457166) - longitude_periapsis;
  598. ctx->entity_registry->assign<entity::component::orbit>(planet_eid, orbit);
  599. // Assign planetary terrain component
  600. entity::component::terrain terrain;
  601. terrain.elevation = [](double, double) -> double
  602. {
  603. //return math::random<double>(0.0, 1.0);
  604. return 0.0;
  605. };
  606. terrain.max_lod = 0;
  607. terrain.patch_material = nullptr;
  608. ctx->entity_registry->assign<entity::component::terrain>(planet_eid, terrain);
  609. // Assign planetary atmosphere component
  610. entity::component::atmosphere atmosphere;
  611. atmosphere.exosphere_altitude = 65e3;
  612. atmosphere.index_of_refraction = 1.000293;
  613. atmosphere.rayleigh_density = 2.545e25;
  614. atmosphere.rayleigh_scale_height = 8000.0;
  615. atmosphere.mie_density = 14.8875;
  616. atmosphere.mie_scale_height = 1200.0;
  617. atmosphere.mie_anisotropy = 0.8;
  618. ctx->entity_registry->assign<entity::component::atmosphere>(planet_eid, atmosphere);
  619. // Assign planetary transform component
  620. entity::component::transform transform;
  621. transform.local = math::identity_transform<float>;
  622. transform.warp = true;
  623. ctx->entity_registry->assign<entity::component::transform>(planet_eid, transform);
  624. // Pass planet to astronomy system as reference body
  625. ctx->astronomy_system->set_reference_body(planet_eid);
  626. // Load sky model
  627. ctx->surface_sky_pass->set_sky_model(ctx->resource_manager->load<model>("sky-dome.mdl"));
  628. }
  629. void selenogenesis(game::context* ctx)
  630. {
  631. // Create lunar entity
  632. entity::id moon_eid = ctx->entity_registry->create();
  633. ctx->entities["moon"] = moon_eid;
  634. // Pass moon model to sky pass
  635. ctx->surface_sky_pass->set_moon_model(ctx->resource_manager->load<model>("moon.mdl"));
  636. }
  637. void extrasolar_heliogenesis(game::context* ctx)
  638. {
  639. // Load star catalog
  640. string_table* star_catalog = ctx->resource_manager->load<string_table>("stars.csv");
  641. // Allocate star catalog vertex data
  642. std::size_t star_count = 0;
  643. if (star_catalog->size() > 0)
  644. star_count = star_catalog->size() - 1;
  645. std::size_t star_vertex_size = 7;
  646. std::size_t star_vertex_stride = star_vertex_size * sizeof(float);
  647. float* star_vertex_data = new float[star_count * star_vertex_size];
  648. float* star_vertex = star_vertex_data;
  649. // Build star catalog vertex data
  650. for (std::size_t i = 1; i < star_catalog->size(); ++i)
  651. {
  652. const string_table_row& catalog_row = (*star_catalog)[i];
  653. double ra = 0.0;
  654. double dec = 0.0;
  655. double vmag = 0.0;
  656. double bv_color = 0.0;
  657. // Parse star catalog entry
  658. try
  659. {
  660. ra = std::stod(catalog_row[1]);
  661. dec = std::stod(catalog_row[2]);
  662. vmag = std::stod(catalog_row[3]);
  663. bv_color = std::stod(catalog_row[4]);
  664. }
  665. catch (const std::exception& e)
  666. {
  667. continue;
  668. }
  669. // Convert right ascension and declination from degrees to radians
  670. ra = math::wrap_radians(math::radians(ra));
  671. dec = math::wrap_radians(math::radians(dec));
  672. // Transform spherical equatorial coordinates to rectangular equatorial coordinates
  673. double3 position_bci = geom::spherical::to_cartesian(double3{1.0, dec, ra});
  674. // Transform coordinates from equatorial space to inertial space
  675. physics::frame<double> bci_to_inertial = physics::orbit::inertial::to_bci({0, 0, 0}, 0.0, math::radians(23.4393)).inverse();
  676. double3 position_inertial = bci_to_inertial * position_bci;
  677. // Convert color index to color temperature
  678. double cct = color::index::bv_to_cct(bv_color);
  679. // Calculate XYZ color from color temperature
  680. double3 color_xyz = color::cct::to_xyz(cct);
  681. // Transform XYZ color to ACEScg colorspace
  682. double3 color_acescg = color::xyz::to_acescg(color_xyz);
  683. // Convert apparent magnitude to irradiance (W/m^2)
  684. double vmag_irradiance = std::pow(10.0, 0.4 * (-vmag - 19.0 + 0.4));
  685. // Convert irradiance to illuminance
  686. double vmag_illuminance = vmag_irradiance * (683.0 * 0.14);
  687. // Scale color by illuminance
  688. double3 scaled_color = color_acescg * vmag_illuminance;
  689. // Build vertex
  690. *(star_vertex++) = static_cast<float>(position_inertial.x);
  691. *(star_vertex++) = static_cast<float>(position_inertial.y);
  692. *(star_vertex++) = static_cast<float>(position_inertial.z);
  693. *(star_vertex++) = static_cast<float>(scaled_color.x);
  694. *(star_vertex++) = static_cast<float>(scaled_color.y);
  695. *(star_vertex++) = static_cast<float>(scaled_color.z);
  696. *(star_vertex++) = static_cast<float>(vmag);
  697. }
  698. // Unload star catalog
  699. ctx->resource_manager->unload("stars.csv");
  700. // Allocate stars model
  701. model* stars_model = new model();
  702. // Resize model VBO and upload vertex data
  703. gl::vertex_buffer* vbo = stars_model->get_vertex_buffer();
  704. vbo->resize(star_count * star_vertex_stride, star_vertex_data);
  705. // Free star catalog vertex data
  706. delete[] star_vertex_data;
  707. // Bind vertex attributes to model VAO
  708. gl::vertex_array* vao = stars_model->get_vertex_array();
  709. std::size_t vao_offset = 0;
  710. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, gl::vertex_attribute_type::float_32, star_vertex_stride, 0);
  711. vao_offset += 3;
  712. vao->bind_attribute(VERTEX_COLOR_LOCATION, *vbo, 4, gl::vertex_attribute_type::float_32, star_vertex_stride, sizeof(float) * vao_offset);
  713. // Load star material
  714. material* star_material = ctx->resource_manager->load<material>("fixed-star.mtl");
  715. // Create model group
  716. model_group* stars_model_group = stars_model->add_group("stars");
  717. stars_model_group->set_material(star_material);
  718. stars_model_group->set_drawing_mode(gl::drawing_mode::points);
  719. stars_model_group->set_start_index(0);
  720. stars_model_group->set_index_count(star_count);
  721. // Pass stars model to sky pass
  722. ctx->surface_sky_pass->set_stars_model(stars_model);
  723. }
  724. void colonigenesis(game::context* ctx)
  725. {}
  726. } // namespace loading
  727. } // namespace state
  728. } // namespace game