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

292 lines
10 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 "entity/components/atmosphere.hpp"
  23. #include "entity/components/behavior.hpp"
  24. #include "entity/components/collision.hpp"
  25. #include "entity/components/diffuse-reflector.hpp"
  26. #include "entity/components/terrain.hpp"
  27. #include "entity/components/transform.hpp"
  28. #include "entity/components/model.hpp"
  29. #include "entity/components/orbit.hpp"
  30. #include "entity/components/blackbody.hpp"
  31. #include "entity/components/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. entity::component::atmosphere component;
  40. if (element.contains("exosphere_altitude"))
  41. component.exosphere_altitude = element["exosphere_altitude"].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_density"))
  45. component.rayleigh_density = element["rayleigh_density"].get<double>();
  46. if (element.contains("mie_density"))
  47. component.mie_density = element["mie_density"].get<double>();
  48. if (element.contains("rayleigh_scale_height"))
  49. component.rayleigh_scale_height = element["rayleigh_scale_height"].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("airglow"))
  55. component.airglow = element["airglow"].get<double>();
  56. if (element.contains("air_concentration"))
  57. component.air_concentration = element["air_concentration"].get<double>();
  58. if (element.contains("ozone_concentration"))
  59. component.ozone_concentration = element["ozone_concentration"].get<double>();
  60. if (element.contains("ozone_lower_limit"))
  61. component.ozone_lower_limit = element["ozone_lower_limit"].get<double>();
  62. if (element.contains("ozone_upper_limit"))
  63. component.ozone_upper_limit = element["ozone_upper_limit"].get<double>();
  64. if (element.contains("ozone_mode"))
  65. component.ozone_mode = element["ozone_mode"].get<double>();
  66. archetype.set<entity::component::atmosphere>(component);
  67. return true;
  68. }
  69. static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  70. {
  71. entity::component::behavior component;
  72. component.behavior_tree = nullptr;
  73. if (element.contains("file"))
  74. {
  75. component.behavior_tree = resource_manager.load<entity::ebt::node>(element["file"].get<std::string>());
  76. }
  77. archetype.set<entity::component::behavior>(component);
  78. return (component.behavior_tree != nullptr);
  79. }
  80. static bool load_component_blackbody(entity::archetype& archetype, const json& element)
  81. {
  82. entity::component::blackbody component;
  83. component.temperature = 0.0;
  84. if (element.contains("temperature"))
  85. component.temperature = element["temperature"].get<double>();
  86. archetype.set<entity::component::blackbody>(component);
  87. return true;
  88. }
  89. static bool load_component_celestial_body(entity::archetype& archetype, const json& element)
  90. {
  91. entity::component::celestial_body component;
  92. if (element.contains("radius"))
  93. component.radius = element["radius"].get<double>();
  94. if (element.contains("mass"))
  95. component.mass = element["mass"].get<double>();
  96. if (element.contains("pole_ra"))
  97. {
  98. component.pole_ra.clear();
  99. auto& pole_ra_element = element["pole_ra"];
  100. for (auto it = pole_ra_element.rbegin(); it != pole_ra_element.rend(); ++it)
  101. component.pole_ra.push_back(math::radians(it->get<double>()));
  102. }
  103. if (element.contains("pole_dec"))
  104. {
  105. component.pole_dec.clear();
  106. auto& pole_dec_element = element["pole_dec"];
  107. for (auto it = pole_dec_element.rbegin(); it != pole_dec_element.rend(); ++it)
  108. component.pole_dec.push_back(math::radians(it->get<double>()));
  109. }
  110. if (element.contains("prime_meridian"))
  111. {
  112. component.prime_meridian.clear();
  113. auto& prime_meridian_element = element["prime_meridian"];
  114. for (auto it = prime_meridian_element.rbegin(); it != prime_meridian_element.rend(); ++it)
  115. component.prime_meridian.push_back(math::radians(it->get<double>()));
  116. }
  117. if (element.contains("albedo"))
  118. component.albedo = element["albedo"].get<double>();
  119. archetype.set<entity::component::celestial_body>(component);
  120. return true;
  121. }
  122. static bool load_component_collision(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  123. {
  124. entity::component::collision component;
  125. component.mesh = nullptr;
  126. if (element.contains("file"))
  127. {
  128. component.mesh = resource_manager.load<geom::mesh>(element["file"].get<std::string>());
  129. }
  130. archetype.set<entity::component::collision>(component);
  131. return (component.mesh != nullptr);
  132. }
  133. static bool load_component_diffuse_reflector(entity::archetype& archetype, const json& element)
  134. {
  135. entity::component::diffuse_reflector component;
  136. component.albedo = 0.0;
  137. if (element.contains("albedo"))
  138. component.albedo = element["albedo"].get<double>();
  139. archetype.set<entity::component::diffuse_reflector>(component);
  140. return true;
  141. }
  142. static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  143. {
  144. entity::component::model component;
  145. component.instance_count = 0;
  146. //component.layers = ~0;
  147. component.layers = 1;
  148. if (element.contains("file"))
  149. {
  150. component.render_model = resource_manager.load<render::model>(element["file"].get<std::string>());
  151. }
  152. archetype.set<entity::component::model>(component);
  153. return true;
  154. }
  155. static bool load_component_orbit(entity::archetype& archetype, const json& element)
  156. {
  157. entity::component::orbit component;
  158. component.parent = entt::null;
  159. component.ephemeris_index = -1;
  160. component.scale = 1.0;
  161. component.position = {0, 0, 0};
  162. if (element.contains("ephemeris_index"))
  163. component.ephemeris_index = element["ephemeris_index"].get<int>();
  164. if (element.contains("scale"))
  165. component.scale = element["scale"].get<double>();
  166. archetype.set<entity::component::orbit>(component);
  167. return true;
  168. }
  169. static bool load_component_transform(entity::archetype& archetype, const json& element)
  170. {
  171. entity::component::transform component;
  172. component.local = math::transform<float>::identity;
  173. component.warp = true;
  174. if (element.contains("translation"))
  175. {
  176. auto translation = element["translation"];
  177. component.local.translation.x = translation[0].get<float>();
  178. component.local.translation.y = translation[1].get<float>();
  179. component.local.translation.z = translation[2].get<float>();
  180. }
  181. if (element.contains("rotation"))
  182. {
  183. auto translation = element["rotation"];
  184. component.local.rotation.w = translation[0].get<float>();
  185. component.local.rotation.x = translation[1].get<float>();
  186. component.local.rotation.y = translation[2].get<float>();
  187. component.local.rotation.z = translation[3].get<float>();
  188. }
  189. if (element.contains("scale"))
  190. {
  191. auto translation = element["scale"];
  192. component.local.scale.x = translation[0].get<float>();
  193. component.local.scale.y = translation[1].get<float>();
  194. component.local.scale.z = translation[2].get<float>();
  195. }
  196. component.world = component.local;
  197. archetype.set<entity::component::transform>(component);
  198. return true;
  199. }
  200. static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, json::const_iterator element)
  201. {
  202. if (element.key() == "atmosphere")
  203. return load_component_atmosphere(archetype, element.value());
  204. if (element.key() == "behavior")
  205. return load_component_behavior(archetype, resource_manager, element.value());
  206. if (element.key() == "blackbody")
  207. return load_component_blackbody(archetype, element.value());
  208. if (element.key() == "celestial_body")
  209. return load_component_celestial_body(archetype, element.value());
  210. if (element.key() == "collision")
  211. return load_component_collision(archetype, resource_manager, element.value());
  212. if (element.key() == "diffuse_reflector")
  213. return load_component_diffuse_reflector(archetype, element.value());
  214. if (element.key() == "model")
  215. return load_component_model(archetype, resource_manager, element.value());
  216. if (element.key() == "orbit")
  217. return load_component_orbit(archetype, element.value());
  218. if (element.key() == "transform")
  219. return load_component_transform(archetype, element.value());
  220. //throw std::runtime_error("Unknown component type \"" + element.key() + "\"");
  221. return true;
  222. }
  223. template <>
  224. entity::archetype* resource_loader<entity::archetype>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  225. {
  226. // Allocate archetype
  227. entity::archetype* archetype = new entity::archetype(resource_manager->get_archetype_registry());
  228. // Read file into buffer
  229. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  230. std::string buffer;
  231. buffer.resize(size);
  232. PHYSFS_readBytes(file, &buffer[0], size);
  233. // Parse JSON data from file buffer
  234. json data = nlohmann::json::parse(buffer, nullptr, true, true);
  235. // Load components from table rows
  236. for (json::const_iterator element = data.cbegin(); element != data.cend(); ++element)
  237. {
  238. if (!load_component(*archetype, *resource_manager, element))
  239. {
  240. throw std::runtime_error("Failed to load component \"" + element.key() + "\"");
  241. }
  242. }
  243. return archetype;
  244. }