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

358 lines
11 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 "resource-loader.hpp"
  20. #include "resource-manager.hpp"
  21. #include "render/model.hpp"
  22. #include "game/component/atmosphere.hpp"
  23. #include "game/component/behavior.hpp"
  24. #include "game/component/collision.hpp"
  25. #include "game/component/diffuse-reflector.hpp"
  26. #include "game/component/terrain.hpp"
  27. #include "game/component/transform.hpp"
  28. #include "game/component/model.hpp"
  29. #include "game/component/orbit.hpp"
  30. #include "game/component/blackbody.hpp"
  31. #include "game/component/celestial-body.hpp"
  32. #include "entity/archetype.hpp"
  33. #include "entity/ebt.hpp"
  34. #include "physics/orbit/elements.hpp"
  35. #include "resources/json.hpp"
  36. #include <stdexcept>
  37. static bool load_component_atmosphere(entity::archetype& archetype, const json& element)
  38. {
  39. game::component::atmosphere component;
  40. if (element.contains("upper_limit"))
  41. component.upper_limit = element["upper_limit"].get<double>();
  42. if (element.contains("index_of_refraction"))
  43. component.index_of_refraction = element["index_of_refraction"].get<double>();
  44. if (element.contains("rayleigh_concentration"))
  45. component.rayleigh_concentration = element["rayleigh_concentration"].get<double>();
  46. if (element.contains("rayleigh_scale_height"))
  47. component.rayleigh_scale_height = element["rayleigh_scale_height"].get<double>();
  48. if (element.contains("mie_concentration"))
  49. component.mie_concentration = element["mie_concentration"].get<double>();
  50. if (element.contains("mie_scale_height"))
  51. component.mie_scale_height = element["mie_scale_height"].get<double>();
  52. if (element.contains("mie_anisotropy"))
  53. component.mie_anisotropy = element["mie_anisotropy"].get<double>();
  54. if (element.contains("mie_albedo"))
  55. component.mie_albedo = element["mie_albedo"].get<double>();
  56. if (element.contains("ozone_concentration"))
  57. component.ozone_concentration = element["ozone_concentration"].get<double>();
  58. if (element.contains("ozone_lower_limit"))
  59. component.ozone_lower_limit = element["ozone_lower_limit"].get<double>();
  60. if (element.contains("ozone_upper_limit"))
  61. component.ozone_upper_limit = element["ozone_upper_limit"].get<double>();
  62. if (element.contains("ozone_mode"))
  63. component.ozone_mode = element["ozone_mode"].get<double>();
  64. if (element.contains("airglow_illuminance"))
  65. {
  66. const auto& airglow_illuminance = element["airglow_illuminance"];
  67. component.airglow_illuminance.x() = airglow_illuminance[0].get<double>();
  68. component.airglow_illuminance.y() = airglow_illuminance[1].get<double>();
  69. component.airglow_illuminance.z() = airglow_illuminance[2].get<double>();
  70. }
  71. archetype.stamps.push_back
  72. (
  73. [component](entt::handle& handle)
  74. {
  75. handle.emplace_or_replace<decltype(component)>(component);
  76. }
  77. );
  78. return true;
  79. }
  80. /*
  81. static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  82. {
  83. game::component::behavior component;
  84. component.behavior_tree = nullptr;
  85. if (element.contains("file"))
  86. {
  87. component.behavior_tree = resource_manager.load<entity::ebt::node>(element["file"].get<std::string>());
  88. }
  89. archetype.stamps.push_back
  90. (
  91. [component](entt::handle& handle)
  92. {
  93. handle.emplace_or_replace<decltype(component)>(component);
  94. }
  95. );
  96. return (component.behavior_tree != nullptr);
  97. }
  98. */
  99. static bool load_component_blackbody(entity::archetype& archetype, const json& element)
  100. {
  101. game::component::blackbody component;
  102. component.temperature = 0.0;
  103. if (element.contains("temperature"))
  104. component.temperature = element["temperature"].get<double>();
  105. archetype.stamps.push_back
  106. (
  107. [component](entt::handle& handle)
  108. {
  109. handle.emplace_or_replace<decltype(component)>(component);
  110. }
  111. );
  112. return true;
  113. }
  114. static bool load_component_celestial_body(entity::archetype& archetype, const json& element)
  115. {
  116. game::component::celestial_body component;
  117. if (element.contains("radius"))
  118. component.radius = element["radius"].get<double>();
  119. if (element.contains("mass"))
  120. component.mass = element["mass"].get<double>();
  121. if (element.contains("pole_ra"))
  122. {
  123. component.pole_ra.clear();
  124. auto& pole_ra_element = element["pole_ra"];
  125. for (auto it = pole_ra_element.rbegin(); it != pole_ra_element.rend(); ++it)
  126. component.pole_ra.push_back(math::radians(it->get<double>()));
  127. }
  128. if (element.contains("pole_dec"))
  129. {
  130. component.pole_dec.clear();
  131. auto& pole_dec_element = element["pole_dec"];
  132. for (auto it = pole_dec_element.rbegin(); it != pole_dec_element.rend(); ++it)
  133. component.pole_dec.push_back(math::radians(it->get<double>()));
  134. }
  135. if (element.contains("prime_meridian"))
  136. {
  137. component.prime_meridian.clear();
  138. auto& prime_meridian_element = element["prime_meridian"];
  139. for (auto it = prime_meridian_element.rbegin(); it != prime_meridian_element.rend(); ++it)
  140. component.prime_meridian.push_back(math::radians(it->get<double>()));
  141. }
  142. if (element.contains("albedo"))
  143. component.albedo = element["albedo"].get<double>();
  144. archetype.stamps.push_back
  145. (
  146. [component](entt::handle& handle)
  147. {
  148. handle.emplace_or_replace<decltype(component)>(component);
  149. }
  150. );
  151. return true;
  152. }
  153. static bool load_component_collision(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  154. {
  155. game::component::collision component;
  156. component.mesh = nullptr;
  157. if (element.contains("file"))
  158. {
  159. component.mesh = resource_manager.load<geom::mesh>(element["file"].get<std::string>());
  160. }
  161. archetype.stamps.push_back
  162. (
  163. [component](entt::handle& handle)
  164. {
  165. handle.emplace_or_replace<decltype(component)>(component);
  166. }
  167. );
  168. return (component.mesh != nullptr);
  169. }
  170. static bool load_component_diffuse_reflector(entity::archetype& archetype, const json& element)
  171. {
  172. game::component::diffuse_reflector component;
  173. component.albedo = 0.0;
  174. if (element.contains("albedo"))
  175. component.albedo = element["albedo"].get<double>();
  176. archetype.stamps.push_back
  177. (
  178. [component](entt::handle& handle)
  179. {
  180. handle.emplace_or_replace<decltype(component)>(component);
  181. }
  182. );
  183. return true;
  184. }
  185. static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  186. {
  187. game::component::model component;
  188. component.instance_count = 0;
  189. //component.layers = ~0;
  190. component.layers = 1;
  191. if (element.contains("file"))
  192. {
  193. component.render_model = resource_manager.load<render::model>(element["file"].get<std::string>());
  194. }
  195. archetype.stamps.push_back
  196. (
  197. [component](entt::handle& handle)
  198. {
  199. handle.emplace_or_replace<decltype(component)>(component);
  200. }
  201. );
  202. return true;
  203. }
  204. static bool load_component_orbit(entity::archetype& archetype, const json& element)
  205. {
  206. game::component::orbit component;
  207. component.parent = entt::null;
  208. component.ephemeris_index = -1;
  209. component.scale = 1.0;
  210. component.position = {0, 0, 0};
  211. if (element.contains("ephemeris_index"))
  212. component.ephemeris_index = element["ephemeris_index"].get<int>();
  213. if (element.contains("scale"))
  214. component.scale = element["scale"].get<double>();
  215. archetype.stamps.push_back
  216. (
  217. [component](entt::handle& handle)
  218. {
  219. handle.emplace_or_replace<decltype(component)>(component);
  220. }
  221. );
  222. return true;
  223. }
  224. static bool load_component_transform(entity::archetype& archetype, const json& element)
  225. {
  226. game::component::transform component;
  227. component.local = math::transform<float>::identity;
  228. component.warp = true;
  229. if (element.contains("translation"))
  230. {
  231. auto translation = element["translation"];
  232. component.local.translation.x() = translation[0].get<float>();
  233. component.local.translation.y() = translation[1].get<float>();
  234. component.local.translation.z() = translation[2].get<float>();
  235. }
  236. if (element.contains("rotation"))
  237. {
  238. auto translation = element["rotation"];
  239. component.local.rotation.w() = translation[0].get<float>();
  240. component.local.rotation.x() = translation[1].get<float>();
  241. component.local.rotation.y() = translation[2].get<float>();
  242. component.local.rotation.z() = translation[3].get<float>();
  243. }
  244. if (element.contains("scale"))
  245. {
  246. auto translation = element["scale"];
  247. component.local.scale.x() = translation[0].get<float>();
  248. component.local.scale.y() = translation[1].get<float>();
  249. component.local.scale.z() = translation[2].get<float>();
  250. }
  251. component.world = component.local;
  252. archetype.stamps.push_back
  253. (
  254. [component](entt::handle& handle)
  255. {
  256. handle.emplace_or_replace<decltype(component)>(component);
  257. }
  258. );
  259. return true;
  260. }
  261. static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, json::const_iterator element)
  262. {
  263. if (element.key() == "atmosphere")
  264. return load_component_atmosphere(archetype, element.value());
  265. // if (element.key() == "behavior")
  266. // return load_component_behavior(archetype, resource_manager, element.value());
  267. if (element.key() == "blackbody")
  268. return load_component_blackbody(archetype, element.value());
  269. if (element.key() == "celestial_body")
  270. return load_component_celestial_body(archetype, element.value());
  271. if (element.key() == "collision")
  272. return load_component_collision(archetype, resource_manager, element.value());
  273. if (element.key() == "diffuse_reflector")
  274. return load_component_diffuse_reflector(archetype, element.value());
  275. if (element.key() == "model")
  276. return load_component_model(archetype, resource_manager, element.value());
  277. if (element.key() == "orbit")
  278. return load_component_orbit(archetype, element.value());
  279. if (element.key() == "transform")
  280. return load_component_transform(archetype, element.value());
  281. //throw std::runtime_error("Unknown component type \"" + element.key() + "\"");
  282. return false;
  283. }
  284. template <>
  285. entity::archetype* resource_loader<entity::archetype>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  286. {
  287. // Allocate archetype
  288. entity::archetype* archetype = new entity::archetype();
  289. // Read file into buffer
  290. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  291. std::string buffer;
  292. buffer.resize(size);
  293. PHYSFS_readBytes(file, &buffer[0], size);
  294. // Parse JSON data from file buffer
  295. json data = nlohmann::json::parse(buffer, nullptr, true, true);
  296. // Load components from table rows
  297. for (json::const_iterator element = data.cbegin(); element != data.cend(); ++element)
  298. {
  299. if (!load_component(*archetype, *resource_manager, element))
  300. {
  301. throw std::runtime_error("Failed to load component \"" + element.key() + "\"");
  302. }
  303. }
  304. return archetype;
  305. }