Antkeeper  0.0.1
entity-archetype-loader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 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 
22 #include <engine/render/model.hpp>
23 #include <engine/math/angles.hpp>
35 #include <engine/utility/json.hpp>
37 #include <stdexcept>
38 
39 static bool load_component_atmosphere(entity::archetype& archetype, const json& element)
40 {
41  ::atmosphere_component component;
42 
43  if (element.contains("upper_limit"))
44  component.upper_limit = element["upper_limit"].get<double>();
45  if (element.contains("index_of_refraction"))
46  component.index_of_refraction = element["index_of_refraction"].get<double>();
47 
48  if (element.contains("rayleigh_concentration"))
49  component.rayleigh_concentration = element["rayleigh_concentration"].get<double>();
50  if (element.contains("rayleigh_scale_height"))
51  component.rayleigh_scale_height = element["rayleigh_scale_height"].get<double>();
52 
53  if (element.contains("mie_concentration"))
54  component.mie_concentration = element["mie_concentration"].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  if (element.contains("mie_albedo"))
60  component.mie_albedo = element["mie_albedo"].get<double>();
61 
62  if (element.contains("ozone_concentration"))
63  component.ozone_concentration = element["ozone_concentration"].get<double>();
64  if (element.contains("ozone_lower_limit"))
65  component.ozone_lower_limit = element["ozone_lower_limit"].get<double>();
66  if (element.contains("ozone_upper_limit"))
67  component.ozone_upper_limit = element["ozone_upper_limit"].get<double>();
68  if (element.contains("ozone_mode"))
69  component.ozone_mode = element["ozone_mode"].get<double>();
70 
71  if (element.contains("airglow_luminance"))
72  {
73  const auto& airglow_luminance = element["airglow_luminance"];
74  component.airglow_luminance.x() = airglow_luminance[0].get<double>();
75  component.airglow_luminance.y() = airglow_luminance[1].get<double>();
76  component.airglow_luminance.z() = airglow_luminance[2].get<double>();
77  }
78 
79  archetype.stamps.push_back
80  (
81  [component](entt::handle& handle)
82  {
83  handle.emplace_or_replace<decltype(component)>(component);
84  }
85  );
86 
87  return true;
88 }
89 
90 static bool load_component_blackbody(entity::archetype& archetype, const json& element)
91 {
92  ::blackbody_component component;
93  component.temperature = 0.0;
94 
95  if (element.contains("temperature"))
96  component.temperature = element["temperature"].get<double>();
97 
98  archetype.stamps.push_back
99  (
100  [component](entt::handle& handle)
101  {
102  handle.emplace_or_replace<decltype(component)>(component);
103  }
104  );
105 
106  return true;
107 }
108 
109 static bool load_component_celestial_body(entity::archetype& archetype, const json& element)
110 {
111  ::celestial_body_component component;
112 
113  if (element.contains("radius"))
114  component.radius = element["radius"].get<double>();
115  if (element.contains("mass"))
116  component.mass = element["mass"].get<double>();
117  if (element.contains("pole_ra"))
118  {
119  component.pole_ra.clear();
120  auto& pole_ra_element = element["pole_ra"];
121  for (auto it = pole_ra_element.rbegin(); it != pole_ra_element.rend(); ++it)
122  component.pole_ra.push_back(math::radians(it->get<double>()));
123  }
124  if (element.contains("pole_dec"))
125  {
126  component.pole_dec.clear();
127  auto& pole_dec_element = element["pole_dec"];
128  for (auto it = pole_dec_element.rbegin(); it != pole_dec_element.rend(); ++it)
129  component.pole_dec.push_back(math::radians(it->get<double>()));
130  }
131  if (element.contains("prime_meridian"))
132  {
133  component.prime_meridian.clear();
134  auto& prime_meridian_element = element["prime_meridian"];
135  for (auto it = prime_meridian_element.rbegin(); it != prime_meridian_element.rend(); ++it)
136  component.prime_meridian.push_back(math::radians(it->get<double>()));
137  }
138  if (element.contains("albedo"))
139  component.albedo = element["albedo"].get<double>();
140 
141  archetype.stamps.push_back
142  (
143  [component](entt::handle& handle)
144  {
145  handle.emplace_or_replace<decltype(component)>(component);
146  }
147  );
148 
149  return true;
150 }
151 
152 static bool load_component_diffuse_reflector(entity::archetype& archetype, const json& element)
153 {
155  component.albedo = 0.0;
156 
157  if (element.contains("albedo"))
158  component.albedo = element["albedo"].get<double>();
159 
160  archetype.stamps.push_back
161  (
162  [component](entt::handle& handle)
163  {
164  handle.emplace_or_replace<decltype(component)>(component);
165  }
166  );
167 
168  return true;
169 }
170 
171 static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const json& element)
172 {
173  std::shared_ptr<render::model> model;
174  if (element.contains("file"))
175  {
176  model = resource_manager.load<render::model>(element["file"].get<std::string>());
177  }
178 
179  archetype.stamps.push_back
180  (
181  [model](entt::handle& handle)
182  {
183  handle.emplace_or_replace<scene_component>
184  (
185  std::make_shared<scene::static_mesh>(model),
186  std::uint8_t{0b00000001}
187  );
188  }
189  );
190 
191  return true;
192 }
193 
194 static bool load_component_orbit(entity::archetype& archetype, const json& element)
195 {
196  ::orbit_component component;
197 
198  component.parent = entt::null;
199  component.ephemeris_index = -1;
200  component.scale = 1.0;
201  component.position = {0, 0, 0};
202 
203  if (element.contains("ephemeris_index"))
204  component.ephemeris_index = element["ephemeris_index"].get<int>();
205  if (element.contains("scale"))
206  component.scale = element["scale"].get<double>();
207 
208  archetype.stamps.push_back
209  (
210  [component](entt::handle& handle)
211  {
212  handle.emplace_or_replace<decltype(component)>(component);
213  }
214  );
215 
216  return true;
217 }
218 
219 static bool load_component_transform(entity::archetype& archetype, const json& element)
220 {
221  ::transform_component component;
223 
224  if (element.contains("translation"))
225  {
226  auto translation = element["translation"];
227  component.local.translation.x() = translation[0].get<float>();
228  component.local.translation.y() = translation[1].get<float>();
229  component.local.translation.z() = translation[2].get<float>();
230  }
231 
232  if (element.contains("rotation"))
233  {
234  auto translation = element["rotation"];
235  component.local.rotation.w() = translation[0].get<float>();
236  component.local.rotation.x() = translation[1].get<float>();
237  component.local.rotation.y() = translation[2].get<float>();
238  component.local.rotation.z() = translation[3].get<float>();
239  }
240 
241  if (element.contains("scale"))
242  {
243  auto translation = element["scale"];
244  component.local.scale.x() = translation[0].get<float>();
245  component.local.scale.y() = translation[1].get<float>();
246  component.local.scale.z() = translation[2].get<float>();
247  }
248 
249  component.world = component.local;
250 
251  archetype.stamps.push_back
252  (
253  [component](entt::handle& handle)
254  {
255  handle.emplace_or_replace<decltype(component)>(component);
256  }
257  );
258 
259  return true;
260 }
261 
262 static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, json::const_iterator element)
263 {
264  if (element.key() == "atmosphere")
265  return load_component_atmosphere(archetype, element.value());
266  // if (element.key() == "behavior")
267  // return load_component_behavior(archetype, resource_manager, element.value());
268  if (element.key() == "blackbody")
269  return load_component_blackbody(archetype, element.value());
270  if (element.key() == "celestial_body")
271  return load_component_celestial_body(archetype, element.value());
272  if (element.key() == "diffuse_reflector")
273  return load_component_diffuse_reflector(archetype, element.value());
274  if (element.key() == "model")
275  return load_component_model(archetype, resource_manager, element.value());
276  if (element.key() == "orbit")
277  return load_component_orbit(archetype, element.value());
278  if (element.key() == "transform")
279  return load_component_transform(archetype, element.value());
280 
281  //throw std::runtime_error("Unknown component type \"" + element.key() + "\"");
282 
283  return false;
284 }
285 
286 template <>
288 {
289  // Load JSON data
291 
292  // Allocate archetype
293  std::unique_ptr<entity::archetype> archetype = std::make_unique<entity::archetype>();
294 
295  // Load components from table rows
296  for (json::const_iterator element = json_data->cbegin(); element != json_data->cend(); ++element)
297  {
298  if (!load_component(*archetype, resource_manager, element))
299  {
300  throw std::runtime_error("Failed to load component \"" + element.key() + "\"");
301  }
302  }
303 
304  return archetype;
305 }
static std::unique_ptr< T > load(::resource_manager &resource_manager, deserialize_context &ctx)
Loads a resource.
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
nlohmann::json json
JSON data.
Definition: json.hpp:26
constexpr T radians(T degrees) noexcept
Converts an angle given in degrees to radians.
Definition: angles.hpp:48
double mie_albedo
Mie single-scattering albedo.
double ozone_mode
Elevation of the mode of the triangular distribution of ozone particles, in meters.
double upper_limit
Elevation of the upper limit of the atmosphere, in meters.
math::dvec3 airglow_luminance
Airglow luminance, in cd/m^2.
double mie_concentration
Molar concentration of Mie particles at sea level, in mol/m-3.
double rayleigh_concentration
Molar concentration of Rayleigh particles at sea level, in mol/m-3.
double ozone_upper_limit
Elevation of the upper limit of the triangular distribution of ozone particles, in meters.
double ozone_lower_limit
Elevation of the lower limit of the triangular distribution of ozone particles, in meters.
double mie_anisotropy
Mie phase function anisotropy factor.
double ozone_concentration
Concentration of ozone in the atmosphere, unitless.
double index_of_refraction
Index of refraction of air at sea level.
double rayleigh_scale_height
Scale height of the exponential distribution of Rayleigh particles, in meters.
double mie_scale_height
Scale height of the exponential distribution of Mie particles, in meters.
Blackbody radiator.
double temperature
Effective temperature, in Kelvin.
std::vector< double > pole_dec
Polynomial coefficients, in descending order of degree, of the declination of the body's north pole,...
double albedo
Geometric albedo.
std::vector< double > prime_meridian
Polynomial coefficients, in descending order of degree, of the rotation state of the body's prime mer...
double mass
Mass of the body, in kilograms.
std::vector< double > pole_ra
Polynomial coefficients, in descending order of degree, of the right ascension of the body's north po...
double radius
Mean radius of the body, in meters.
Provides access to a deserialization state.
Entity type template.
Definition: archetype.hpp:34
std::list< std::function< void(entt::handle &)> > stamps
List of stamp functions which construct instances of the archetype's components.
Definition: archetype.hpp:36
constexpr scalar_type & w() noexcept
Returns a reference to the quaternion real part.
Definition: quaternion.hpp:57
constexpr scalar_type & y() noexcept
Returns a reference to the second element of the quaternion imaginary part.
Definition: quaternion.hpp:81
constexpr scalar_type & z() noexcept
Returns a reference to the third element of the quaternion imaginary part.
Definition: quaternion.hpp:93
constexpr scalar_type & x() noexcept
Returns a reference to the first element of the quaternion imaginary part.
Definition: quaternion.hpp:69
vector_type scale
Scale vector.
Definition: transform.hpp:56
static constexpr transform identity() noexcept
Returns an identity transform.
Definition: transform.hpp:107
vector_type translation
Translation vector.
Definition: transform.hpp:50
quaternion_type rotation
Rotation quaternion.
Definition: transform.hpp:53
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
constexpr element_type & z() noexcept
Returns a reference to the third element.
Definition: vector.hpp:196
int ephemeris_index
Index of the orbit in the ephemeris.
math::dvec3 position
Cartesian position of the orbit, w.r.t. the ICRF frame.
entity::id parent
Entity ID of the parent orbit.
double scale
Orbit scale, for two-body orbits with one ephemeris item.
math::transform< float > world
math::transform< float > local