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

263 lines
8.8 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 "renderer/model.hpp"
  22. #include "entity/components/atmosphere.hpp"
  23. #include "entity/components/behavior.hpp"
  24. #include "entity/components/collision.hpp"
  25. #include "entity/components/terrain.hpp"
  26. #include "entity/components/transform.hpp"
  27. #include "entity/components/model.hpp"
  28. #include "entity/components/orbit.hpp"
  29. #include "entity/components/blackbody.hpp"
  30. #include "entity/components/celestial-body.hpp"
  31. #include "entity/archetype.hpp"
  32. #include "entity/ebt.hpp"
  33. #include "resources/json.hpp"
  34. #include <stdexcept>
  35. static bool load_component_atmosphere(entity::archetype& archetype, const json& element)
  36. {
  37. entity::component::atmosphere component;
  38. component.exosphere_altitude = 0.0;
  39. component.index_of_refraction = 0.0;
  40. component.rayleigh_density = 0.0;
  41. component.mie_density = 0.0;
  42. component.rayleigh_scale_height = 0.0;
  43. component.mie_scale_height = 0.0;
  44. component.mie_anisotropy = 0.0;
  45. if (element.contains("exosphere_altitude"))
  46. component.exosphere_altitude = element["exosphere_altitude"].get<double>();
  47. if (element.contains("index_of_refraction"))
  48. component.index_of_refraction = element["index_of_refraction"].get<double>();
  49. if (element.contains("rayleigh_density"))
  50. component.rayleigh_density = element["rayleigh_density"].get<double>();
  51. if (element.contains("mie_density"))
  52. component.mie_density = element["mie_density"].get<double>();
  53. if (element.contains("rayleigh_scale_height"))
  54. component.rayleigh_scale_height = element["rayleigh_scale_height"].get<double>();
  55. if (element.contains("mie_scale_height"))
  56. component.mie_scale_height = element["mie_scale_height"].get<double>();
  57. if (element.contains("mie_anisotropy"))
  58. component.mie_anisotropy = element["mie_anisotropy"].get<double>();
  59. archetype.set<entity::component::atmosphere>(component);
  60. return true;
  61. }
  62. static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  63. {
  64. entity::component::behavior component;
  65. component.behavior_tree = nullptr;
  66. if (element.contains("file"))
  67. {
  68. component.behavior_tree = resource_manager.load<entity::ebt::node>(element["file"].get<std::string>());
  69. }
  70. archetype.set<entity::component::behavior>(component);
  71. return (component.behavior_tree != nullptr);
  72. }
  73. static bool load_component_blackbody(entity::archetype& archetype, const json& element)
  74. {
  75. entity::component::blackbody component;
  76. component.temperature = 0.0;
  77. if (element.contains("temperature"))
  78. component.temperature = element["temperature"].get<double>();
  79. archetype.set<entity::component::blackbody>(component);
  80. return true;
  81. }
  82. static bool load_component_celestial_body(entity::archetype& archetype, const json& element)
  83. {
  84. entity::component::celestial_body component;
  85. component.radius = 0.0;
  86. component.axial_tilt = 0.0;
  87. component.axial_rotation = 0.0;
  88. component.angular_frequency = 0.0;
  89. if (element.contains("radius"))
  90. component.radius = element["radius"].get<double>();
  91. if (element.contains("axial_tilt"))
  92. component.axial_tilt = element["axial_tilt"].get<double>();
  93. if (element.contains("axial_rotation"))
  94. component.axial_rotation = element["axial_rotation"].get<double>();
  95. if (element.contains("angular_frequency"))
  96. component.angular_frequency = element["angular_frequency"].get<double>();
  97. archetype.set<entity::component::celestial_body>(component);
  98. return true;
  99. }
  100. static bool load_component_collision(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  101. {
  102. entity::component::collision component;
  103. component.mesh = nullptr;
  104. if (element.contains("file"))
  105. {
  106. component.mesh = resource_manager.load<geom::mesh>(element["file"].get<std::string>());
  107. }
  108. archetype.set<entity::component::collision>(component);
  109. return (component.mesh != nullptr);
  110. }
  111. static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
  112. {
  113. entity::component::model component;
  114. component.instance_count = 0;
  115. component.layers = ~0;
  116. if (element.contains("file"))
  117. {
  118. component.render_model = resource_manager.load<model>(element["file"].get<std::string>());
  119. }
  120. archetype.set<entity::component::model>(component);
  121. return true;
  122. }
  123. static bool load_component_orbit(entity::archetype& archetype, const json& element)
  124. {
  125. entity::component::orbit component;
  126. component.elements.e = 0.0;
  127. component.elements.a = 0.0;
  128. component.elements.i = 0.0;
  129. component.elements.raan = 0.0;
  130. component.elements.w = 0.0;
  131. component.elements.ta = 0.0;
  132. if (element.contains("e"))
  133. component.elements.e = element["e"].get<double>();
  134. if (element.contains("a"))
  135. component.elements.a = element["a"].get<double>();
  136. if (element.contains("i"))
  137. component.elements.i = element["i"].get<double>();
  138. if (element.contains("raan"))
  139. component.elements.raan = element["raan"].get<double>();
  140. if (element.contains("w"))
  141. component.elements.w = element["w"].get<double>();
  142. if (element.contains("ta"))
  143. component.elements.ta = element["ta"].get<double>();
  144. archetype.set<entity::component::orbit>(component);
  145. return true;
  146. }
  147. static bool load_component_transform(entity::archetype& archetype, const json& element)
  148. {
  149. entity::component::transform component;
  150. component.local = math::identity_transform<float>;
  151. component.warp = true;
  152. if (element.contains("translation"))
  153. {
  154. auto translation = element["translation"];
  155. component.local.translation.x = translation[0].get<float>();
  156. component.local.translation.y = translation[1].get<float>();
  157. component.local.translation.z = translation[2].get<float>();
  158. }
  159. if (element.contains("rotation"))
  160. {
  161. auto translation = element["rotation"];
  162. component.local.rotation.w = translation[0].get<float>();
  163. component.local.rotation.x = translation[1].get<float>();
  164. component.local.rotation.y = translation[2].get<float>();
  165. component.local.rotation.z = translation[3].get<float>();
  166. }
  167. if (element.contains("scale"))
  168. {
  169. auto translation = element["scale"];
  170. component.local.scale.x = translation[0].get<float>();
  171. component.local.scale.y = translation[1].get<float>();
  172. component.local.scale.z = translation[2].get<float>();
  173. }
  174. archetype.set<entity::component::transform>(component);
  175. return true;
  176. }
  177. static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, json::const_iterator element)
  178. {
  179. if (element.key() == "atmosphere")
  180. return load_component_atmosphere(archetype, element.value());
  181. if (element.key() == "behavior")
  182. return load_component_behavior(archetype, resource_manager, element.value());
  183. if (element.key() == "blackbody")
  184. return load_component_blackbody(archetype, element.value());
  185. if (element.key() == "celestial_body")
  186. return load_component_celestial_body(archetype, element.value());
  187. if (element.key() == "collision")
  188. return load_component_collision(archetype, resource_manager, element.value());
  189. if (element.key() == "model")
  190. return load_component_model(archetype, resource_manager, element.value());
  191. if (element.key() == "orbit")
  192. return load_component_orbit(archetype, element.value());
  193. if (element.key() == "transform")
  194. return load_component_transform(archetype, element.value());
  195. //throw std::runtime_error("Unknown component type \"" + element.key() + "\"");
  196. return true;
  197. }
  198. template <>
  199. entity::archetype* resource_loader<entity::archetype>::load(resource_manager* resource_manager, PHYSFS_File* file)
  200. {
  201. // Allocate archetype
  202. entity::archetype* archetype = new entity::archetype(resource_manager->get_archetype_registry());
  203. // Read file into buffer
  204. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  205. std::string buffer;
  206. buffer.resize(size);
  207. PHYSFS_readBytes(file, &buffer[0], size);
  208. // Parse JSON data from file buffer
  209. json data = nlohmann::json::parse(buffer, nullptr, true, true);
  210. // Load components from table rows
  211. for (json::const_iterator element = data.cbegin(); element != data.cend(); ++element)
  212. {
  213. if (!load_component(*archetype, *resource_manager, element))
  214. {
  215. throw std::runtime_error("Failed to load component \"" + element.key() + "\"");
  216. }
  217. }
  218. return archetype;
  219. }