From 3a261258de7b60967f45cca5f6baea1aff0e3573 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Sat, 2 Oct 2021 09:57:39 +0800 Subject: [PATCH] Upgrade entity loader to load from JSON files. Closes #9 --- src/resources/entity-archetype-loader.cpp | 286 +++++++++++++--------- src/resources/json.hpp | 2 +- src/resources/material-loader.cpp | 2 +- 3 files changed, 169 insertions(+), 121 deletions(-) diff --git a/src/resources/entity-archetype-loader.cpp b/src/resources/entity-archetype-loader.cpp index 0005cff..06bbceb 100644 --- a/src/resources/entity-archetype-loader.cpp +++ b/src/resources/entity-archetype-loader.cpp @@ -19,197 +19,245 @@ #include "resource-loader.hpp" #include "resource-manager.hpp" -#include "string-table.hpp" #include "renderer/model.hpp" +#include "entity/components/atmosphere.hpp" #include "entity/components/behavior.hpp" #include "entity/components/collision.hpp" #include "entity/components/terrain.hpp" #include "entity/components/transform.hpp" #include "entity/components/model.hpp" -#include "entity/components/nest.hpp" -#include "entity/components/marker.hpp" -#include "entity/components/brush.hpp" +#include "entity/components/orbit.hpp" +#include "entity/components/blackbody.hpp" +#include "entity/components/celestial-body.hpp" #include "entity/archetype.hpp" #include "entity/ebt.hpp" -#include +#include "resources/json.hpp" #include -static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const std::vector& parameters) +static bool load_component_atmosphere(entity::archetype& archetype, const json& element) { - if (parameters.size() != 2) - { - throw std::runtime_error("load_component_behavior(): Invalid parameter count."); - } - - std::string filename = parameters[1]; - entity::component::behavior component; - component.behavior_tree = resource_manager.load(filename); - if (!component.behavior_tree) - { - std::string message = std::string("load_component_behavior(): Failed to load behavior tree \"") + filename + std::string("\""); - throw std::runtime_error(message); - } + entity::component::atmosphere component; + component.exosphere_altitude = 0.0; + component.index_of_refraction = 0.0; + component.rayleigh_density = 0.0; + component.mie_density = 0.0; + component.rayleigh_scale_height = 0.0; + component.mie_scale_height = 0.0; + component.mie_anisotropy = 0.0; + + if (element.contains("exosphere_altitude")) + component.exosphere_altitude = element["exosphere_altitude"].get(); + if (element.contains("index_of_refraction")) + component.index_of_refraction = element["index_of_refraction"].get(); + if (element.contains("rayleigh_density")) + component.rayleigh_density = element["rayleigh_density"].get(); + if (element.contains("mie_density")) + component.mie_density = element["mie_density"].get(); + if (element.contains("rayleigh_scale_height")) + component.rayleigh_scale_height = element["rayleigh_scale_height"].get(); + if (element.contains("mie_scale_height")) + component.mie_scale_height = element["mie_scale_height"].get(); + if (element.contains("mie_anisotropy")) + component.mie_anisotropy = element["mie_anisotropy"].get(); - archetype.set(component); + archetype.set(component); return true; } -static bool load_component_collision(entity::archetype& archetype, resource_manager& resource_manager, const std::vector& parameters) +static bool load_component_behavior(entity::archetype& archetype, resource_manager& resource_manager, const json& element) { - if (parameters.size() != 2) - { - throw std::runtime_error("load_component_collision(): Invalid parameter count."); - } - - std::string filename = parameters[1]; - entity::component::collision component; - component.mesh = resource_manager.load(filename); - if (!component.mesh) + entity::component::behavior component; + component.behavior_tree = nullptr; + + if (element.contains("file")) { - std::string message = std::string("load_component_collision(): Failed to load model \"") + filename + std::string("\""); - throw std::runtime_error(message); + component.behavior_tree = resource_manager.load(element["file"].get()); } - - archetype.set(component); - - return true; + + archetype.set(component); + + return (component.behavior_tree != nullptr); } -static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const std::vector& parameters) +static bool load_component_blackbody(entity::archetype& archetype, const json& element) { - if (parameters.size() != 2) - { - throw std::runtime_error("load_component_model(): Invalid parameter count."); - } - - std::string filename = parameters[1]; - entity::component::model component; - component.render_model = resource_manager.load(filename); - component.instance_count = 0; - component.layers = 1; - if (!component.render_model) - { - std::string message = std::string("load_component_model(): Failed to load model \"") + filename + std::string("\""); - throw std::runtime_error(message); - } + entity::component::blackbody component; + component.temperature = 0.0; + + if (element.contains("temperature")) + component.temperature = element["temperature"].get(); - archetype.set(component); + archetype.set(component); return true; } -static bool load_component_nest(entity::archetype& archetype, const std::vector& parameters) +static bool load_component_celestial_body(entity::archetype& archetype, const json& element) { - entity::component::nest component; - archetype.set(component); + entity::component::celestial_body component; + component.radius = 0.0; + component.axial_tilt = 0.0; + component.axial_rotation = 0.0; + component.angular_frequency = 0.0; + + if (element.contains("radius")) + component.radius = element["radius"].get(); + if (element.contains("axial_tilt")) + component.axial_tilt = element["axial_tilt"].get(); + if (element.contains("axial_rotation")) + component.axial_rotation = element["axial_rotation"].get(); + if (element.contains("angular_frequency")) + component.angular_frequency = element["angular_frequency"].get(); + + archetype.set(component); return true; } -static bool load_component_marker(entity::archetype& archetype, const std::vector& parameters) +static bool load_component_collision(entity::archetype& archetype, resource_manager& resource_manager, const json& element) { - if (parameters.size() != 2) + entity::component::collision component; + component.mesh = nullptr; + + if (element.contains("file")) { - throw std::runtime_error("load_component_marker(): Invalid parameter count."); + component.mesh = resource_manager.load(element["file"].get()); } - entity::component::marker component; - component.color = std::stoi(parameters[1]); - archetype.set(component); + archetype.set(component); - return true; + return (component.mesh != nullptr); } -static bool load_component_brush(entity::archetype& archetype, const std::vector& parameters) +static bool load_component_model(entity::archetype& archetype, resource_manager& resource_manager, const json& element) { - if (parameters.size() != 2) + entity::component::model component; + component.instance_count = 0; + component.layers = ~0; + + if (element.contains("file")) { - throw std::runtime_error("load_component_brush(): Invalid parameter count."); + component.render_model = resource_manager.load(element["file"].get()); } - entity::component::brush component; - component.radius = std::stof(parameters[1]); - archetype.set(component); + archetype.set(component); return true; } -static bool load_component_transform(entity::archetype& archetype, const std::vector& parameters) +static bool load_component_orbit(entity::archetype& archetype, const json& element) { - if (parameters.size() != 11) - { - throw std::runtime_error("load_component_transform(): Invalid parameter count."); - } + entity::component::orbit component; + + component.elements.e = 0.0; + component.elements.a = 0.0; + component.elements.i = 0.0; + component.elements.raan = 0.0; + component.elements.w = 0.0; + component.elements.ta = 0.0; + + if (element.contains("e")) + component.elements.e = element["e"].get(); + if (element.contains("a")) + component.elements.a = element["a"].get(); + if (element.contains("i")) + component.elements.i = element["i"].get(); + if (element.contains("raan")) + component.elements.raan = element["raan"].get(); + if (element.contains("w")) + component.elements.w = element["w"].get(); + if (element.contains("ta")) + component.elements.ta = element["ta"].get(); - std::stringstream stream; - for (std::size_t i = 1; i < parameters.size(); ++i) - { - stream << parameters[i]; - if (i < parameters.size() - 1) - stream << ' '; - } + archetype.set(component); + + return true; +} +static bool load_component_transform(entity::archetype& archetype, const json& element) +{ entity::component::transform component; - stream >> component.local.translation.x; - stream >> component.local.translation.y; - stream >> component.local.translation.z; - stream >> component.local.rotation.w; - stream >> component.local.rotation.x; - stream >> component.local.rotation.y; - stream >> component.local.rotation.z; - stream >> component.local.scale.x; - stream >> component.local.scale.y; - stream >> component.local.scale.z; + component.local = math::identity_transform; component.warp = true; + + if (element.contains("translation")) + { + auto translation = element["translation"]; + component.local.translation.x = translation[0].get(); + component.local.translation.y = translation[1].get(); + component.local.translation.z = translation[2].get(); + } + + if (element.contains("rotation")) + { + auto translation = element["rotation"]; + component.local.rotation.w = translation[0].get(); + component.local.rotation.x = translation[1].get(); + component.local.rotation.y = translation[2].get(); + component.local.rotation.z = translation[3].get(); + } + + if (element.contains("scale")) + { + auto translation = element["scale"]; + component.local.scale.x = translation[0].get(); + component.local.scale.y = translation[1].get(); + component.local.scale.z = translation[2].get(); + } archetype.set(component); return true; } -static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, const std::vector& parameters) +static bool load_component(entity::archetype& archetype, resource_manager& resource_manager, json::const_iterator element) { - if (parameters[0] == "behavior") return load_component_behavior(archetype, resource_manager, parameters); - if (parameters[0] == "collision") return load_component_collision(archetype, resource_manager, parameters); - if (parameters[0] == "model") return load_component_model(archetype, resource_manager, parameters); - if (parameters[0] == "nest") return load_component_nest(archetype, parameters); - if (parameters[0] == "transform") return load_component_transform(archetype, parameters); - if (parameters[0] == "marker") return load_component_marker(archetype, parameters); - if (parameters[0] == "brush") return load_component_brush(archetype, parameters); - - std::string message = std::string("load_component(): Unknown component type \"") + parameters[0] + std::string("\""); - throw std::runtime_error(message); + if (element.key() == "atmosphere") + return load_component_atmosphere(archetype, element.value()); + if (element.key() == "behavior") + return load_component_behavior(archetype, resource_manager, element.value()); + if (element.key() == "blackbody") + return load_component_blackbody(archetype, element.value()); + if (element.key() == "celestial_body") + return load_component_celestial_body(archetype, element.value()); + if (element.key() == "collision") + return load_component_collision(archetype, resource_manager, element.value()); + if (element.key() == "model") + return load_component_model(archetype, resource_manager, element.value()); + if (element.key() == "orbit") + return load_component_orbit(archetype, element.value()); + if (element.key() == "transform") + return load_component_transform(archetype, element.value()); + + //throw std::runtime_error("Unknown component type \"" + element.key() + "\""); + + return true; } template <> entity::archetype* resource_loader::load(resource_manager* resource_manager, PHYSFS_File* file) { + // Allocate archetype entity::archetype* archetype = new entity::archetype(resource_manager->get_archetype_registry()); - // Load string table from input stream - string_table* table = resource_loader::load(resource_manager, file); - - // Ensure table is not empty. - if (!table || table->empty()) - { - delete table; - return nullptr; - } + // Read file into buffer + std::size_t size = static_cast(PHYSFS_fileLength(file)); + std::string buffer; + buffer.resize(size); + PHYSFS_readBytes(file, &buffer[0], size); + + // Parse JSON data from file buffer + json data = nlohmann::json::parse(buffer, nullptr, true, true); // Load components from table rows - for (const string_table_row& row: *table) + for (json::const_iterator element = data.cbegin(); element != data.cend(); ++element) { - // Skip empty rows and comments - if (row.empty() || row[0].empty() || row[0][0] == '#') + if (!load_component(*archetype, *resource_manager, element)) { - continue; + throw std::runtime_error("Failed to load component \"" + element.key() + "\""); } - - - load_component(*archetype, *resource_manager, row); } return archetype; } - diff --git a/src/resources/json.hpp b/src/resources/json.hpp index 91f26d2..5c9abf0 100644 --- a/src/resources/json.hpp +++ b/src/resources/json.hpp @@ -23,6 +23,6 @@ #include /// JSON data -typedef nlohmann::json json; +using json = nlohmann::json; #endif // ANTKEEPER_RESOURCES_JSON_HPP diff --git a/src/resources/material-loader.cpp b/src/resources/material-loader.cpp index 444068b..258841d 100644 --- a/src/resources/material-loader.cpp +++ b/src/resources/material-loader.cpp @@ -232,7 +232,7 @@ material* resource_loader::load(resource_manager* resource_manager, PH PHYSFS_readBytes(file, &buffer[0], size); // Parse json from file buffer - nlohmann::json json = nlohmann::json::parse(buffer); + nlohmann::json json = nlohmann::json::parse(buffer, nullptr, true, true); // Allocate material material* material = new ::material();