mirror of
https://github.com/harfang3d/harfang3d.git
synced 2024-07-16 15:02:19 +00:00
924 lines
28 KiB
C++
924 lines
28 KiB
C++
// HARFANG(R) Copyright (C) 2021 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
|
|
|
|
#include "engine/file_format.h"
|
|
#include "engine/render_pipeline.h"
|
|
#include "engine/scene.h"
|
|
#include "engine/to_json.h"
|
|
|
|
#include "foundation/format.h"
|
|
#include "foundation/log.h"
|
|
#include <foundation/string.h>
|
|
|
|
#include <json/json.hpp>
|
|
#include <set>
|
|
|
|
namespace hg {
|
|
|
|
void SaveComponent(const Scene::Transform_ *data_, json &js) {
|
|
js["pos"] = data_->TRS.pos;
|
|
js["rot"] = RadianToDegree(data_->TRS.rot);
|
|
js["scl"] = data_->TRS.scl;
|
|
js["parent"] = data_->parent;
|
|
}
|
|
|
|
void SaveComponent(const Scene::Camera_ *data_, json &js) {
|
|
js["zrange"] = data_->zrange;
|
|
js["fov"] = data_->fov;
|
|
js["ortho"] = data_->ortho;
|
|
js["size"] = data_->size;
|
|
}
|
|
|
|
void SaveComponent(const Scene::Object_ *data_, json &js, const PipelineResources &resources) {
|
|
js["name"] = resources.models.GetName(data_->model);
|
|
|
|
const auto mat_count = uint16_t(data_->materials.size());
|
|
|
|
std::vector<json> materials(mat_count);
|
|
for (size_t j = 0; j < mat_count; ++j)
|
|
SaveMaterial(data_->materials[j], materials[j], resources);
|
|
js["materials"] = materials;
|
|
|
|
std::vector<json> material_infos(mat_count);
|
|
for (size_t j = 0; j < mat_count; j++)
|
|
if (j < data_->material_infos.size()) {
|
|
material_infos[j]["name"] = data_->material_infos[j].name;
|
|
} else {
|
|
material_infos[j]["name"] = std::string();
|
|
}
|
|
js["material_infos"] = material_infos;
|
|
|
|
json bones = json::array();
|
|
for (auto bone : data_->bones)
|
|
bones.push_back(bone);
|
|
js["bones"] = bones;
|
|
}
|
|
|
|
void SaveComponent(const Scene::Light_ *data_, json &js) {
|
|
js["type"] = data_->type;
|
|
js["shadow_type"] = data_->shadow_type;
|
|
js["diffuse"] = data_->diffuse;
|
|
js["diffuse_intensity"] = data_->diffuse_intensity;
|
|
js["specular"] = data_->specular;
|
|
js["specular_intensity"] = data_->specular_intensity;
|
|
js["radius"] = data_->radius;
|
|
js["inner_angle"] = data_->inner_angle;
|
|
js["outer_angle"] = data_->outer_angle;
|
|
js["pssm_split"] = data_->pssm_split;
|
|
js["priority"] = data_->priority;
|
|
js["shadow_bias"] = data_->shadow_bias;
|
|
}
|
|
|
|
void SaveComponent(const Scene::RigidBody_ *data_, json &js) {
|
|
js["type"] = data_->type;
|
|
js["world"] = data_->cur;
|
|
js["scale"] = data_->scl;
|
|
js["linear_damping"] = data_->linear_damping;
|
|
js["angular_damping"] = data_->angular_damping;
|
|
js["restitution"] = data_->restitution;
|
|
js["friction"] = data_->friction;
|
|
js["rolling_friction"] = data_->rolling_friction;
|
|
}
|
|
|
|
void SaveComponent(const Scene::Script_ *data_, json &js) {
|
|
js["path"] = data_->path;
|
|
|
|
for (auto &i : data_->params) {
|
|
if (i.second.type == SPT_Bool)
|
|
js["parameters"][i.first] = {{"type", "bool"}, {"value", i.second.bv}};
|
|
else if (i.second.type == SPT_Int)
|
|
js["parameters"][i.first] = {{"type", "int"}, {"value", i.second.iv}};
|
|
else if (i.second.type == SPT_Float)
|
|
js["parameters"][i.first] = {{"type", "float"}, {"value", i.second.fv}};
|
|
else if (i.second.type == SPT_String)
|
|
js["parameters"][i.first] = {{"type", "string"}, {"value", i.second.sv}};
|
|
}
|
|
}
|
|
|
|
void SaveComponent(const Scene::Instance_ *data_, json &js) {
|
|
js["name"] = data_->name;
|
|
|
|
if (!data_->anim.empty()) {
|
|
js["anim"] = data_->anim;
|
|
js["loop_mode"] = data_->loop_mode;
|
|
}
|
|
}
|
|
|
|
void SaveComponent(const Scene::Collision_ *data_, json &js) {
|
|
js["type"] = data_->type;
|
|
js["mass"] = data_->mass;
|
|
js["size"] = data_->size;
|
|
js["path"] = data_->resource_path;
|
|
js["m"] = data_->m;
|
|
}
|
|
|
|
//
|
|
void LoadComponent(Scene::Transform_ *data_, const json &js) {
|
|
data_->TRS.pos = js.at("pos");
|
|
|
|
data_->TRS.rot = DegreeToRadian(js.at("rot").get<Vec3>());
|
|
data_->TRS.scl = js.at("scl");
|
|
data_->parent = js.at("parent");
|
|
}
|
|
|
|
void LoadComponent(Scene::Camera_ *data_, const json &js) {
|
|
js_at_safe(js, "zrange", data_->zrange);
|
|
js_at_safe(js, "fov", data_->fov);
|
|
js_at_safe(js, "ortho", data_->ortho);
|
|
js_at_safe(js, "size", data_->size);
|
|
}
|
|
|
|
void LoadComponent(Scene::Object_ *data_, const json &js, const Reader &deps_ir, const ReadProvider &deps_ip, PipelineResources &resources,
|
|
const PipelineInfo &pipeline, bool queue_texture_loads, bool do_not_load_resources) {
|
|
const std::string name = js.at("name");
|
|
|
|
if (!name.empty()) {
|
|
if (do_not_load_resources)
|
|
data_->model = resources.models.Add(name.c_str(), {});
|
|
else
|
|
data_->model = LoadModel(deps_ir, deps_ip, name.c_str(), resources);
|
|
}
|
|
|
|
const auto i_mats = js.find("materials");
|
|
if (i_mats != std::end(js)) {
|
|
const auto &mats = *i_mats;
|
|
const auto mat_count = mats.size();
|
|
data_->materials.resize(mat_count);
|
|
for (size_t i = 0; i < mat_count; ++i)
|
|
data_->materials[i] = LoadMaterial(mats[i], deps_ir, deps_ip, resources, pipeline, queue_texture_loads, do_not_load_resources);
|
|
}
|
|
|
|
const auto i_mat_infos = js.find("material_infos");
|
|
if (i_mat_infos != std::end(js)) {
|
|
const auto &mat_infos = *i_mat_infos;
|
|
const auto mat_count = data_->materials.size();
|
|
data_->material_infos.resize(mat_count);
|
|
for (size_t i = 0; i < mat_count; ++i) {
|
|
if (i == mat_infos.size())
|
|
break;
|
|
mat_infos[i]["name"].get_to(data_->material_infos[i].name);
|
|
}
|
|
}
|
|
|
|
const auto i_bones = js.find("bones");
|
|
if (i_bones != std::end(js)) {
|
|
const auto &bones = *i_bones;
|
|
const auto bone_count = bones.size();
|
|
data_->bones.resize(bone_count);
|
|
for (size_t i = 0; i < bone_count; ++i)
|
|
data_->bones[i] = bones[i];
|
|
}
|
|
}
|
|
|
|
void LoadComponent(Scene::Light_ *data_, const json &js) {
|
|
data_->type = js["type"];
|
|
if (js.find("shadow_type") != std::end(js))
|
|
data_->shadow_type = js["shadow_type"];
|
|
data_->diffuse = js["diffuse"];
|
|
if (js.contains("diffuse_intensity"))
|
|
data_->diffuse_intensity = js["diffuse_intensity"];
|
|
data_->specular = js["specular"];
|
|
if (js.contains("specular_intensity"))
|
|
data_->specular_intensity = js["specular_intensity"];
|
|
data_->radius = js["radius"];
|
|
data_->inner_angle = js["inner_angle"];
|
|
data_->outer_angle = js["outer_angle"];
|
|
if (js.find("pssm_split") != std::end(js))
|
|
data_->pssm_split = js["pssm_split"];
|
|
data_->priority = js["priority"];
|
|
if (js.find("shadow_bias") != std::end(js))
|
|
data_->shadow_bias = js["shadow_bias"];
|
|
}
|
|
|
|
void LoadComponent(Scene::RigidBody_ *data_, const json &js) {
|
|
data_->type = js.at("type");
|
|
data_->cur = js.at("world");
|
|
if (js.find("scale") != std::end(js))
|
|
data_->scl = js.at("scale");
|
|
if (js.find("linear_damping") != std::end(js))
|
|
data_->linear_damping = js.at("linear_damping");
|
|
if (js.find("angular_damping") != std::end(js))
|
|
data_->angular_damping = js.at("angular_damping");
|
|
if (js.find("restitution") != std::end(js))
|
|
data_->restitution = js.at("restitution");
|
|
if (js.find("friction") != std::end(js))
|
|
data_->friction = js.at("friction");
|
|
if (js.find("rolling_friction") != std::end(js))
|
|
data_->rolling_friction = js.at("rolling_friction");
|
|
}
|
|
|
|
void LoadComponent(Scene::Script_ *data_, const json &js) {
|
|
data_->path = js["path"].get<std::string>();
|
|
|
|
const auto j = js.find("parameters");
|
|
|
|
if (j != std::end(js))
|
|
for (auto i : j->items()) {
|
|
auto &v = i.value();
|
|
const auto type = v["type"].get<std::string>();
|
|
|
|
ScriptParam parm{};
|
|
|
|
if (type == "bool") {
|
|
parm.type = SPT_Bool;
|
|
parm.bv = v["value"].get<bool>();
|
|
} else if (type == "int") {
|
|
parm.type = SPT_Int;
|
|
parm.iv = v["value"].get<int>();
|
|
} else if (type == "float") {
|
|
parm.type = SPT_Float;
|
|
parm.fv = v["value"].get<float>();
|
|
} else if (type == "string") {
|
|
parm.type = SPT_String;
|
|
parm.sv = v["value"].get<std::string>();
|
|
}
|
|
|
|
data_->params[i.key()] = std::move(parm);
|
|
}
|
|
}
|
|
|
|
void LoadComponent(Scene::Instance_ *data_, const json &js) {
|
|
js["name"].get_to(data_->name);
|
|
|
|
if (js.find("anim") != std::end(js)) {
|
|
js["anim"].get_to(data_->anim);
|
|
data_->loop_mode = js["loop_mode"];
|
|
}
|
|
}
|
|
|
|
void LoadComponent(Scene::Collision_ *data_, const json &js) {
|
|
data_->type = js["type"];
|
|
data_->mass = js["mass"];
|
|
data_->size = js["size"];
|
|
data_->resource_path = js["path"].get<std::string>();
|
|
data_->m = js["m"];
|
|
}
|
|
|
|
//
|
|
bool Scene::Save_json(json &js, const PipelineResources &resources, uint32_t save_flags, const std::vector<NodeRef> *nodes_to_save) const {
|
|
// prepare list of nodes to save
|
|
std::vector<NodeRef> node_refs;
|
|
|
|
if (save_flags & LSSF_Nodes) {
|
|
if (nodes_to_save) {
|
|
node_refs = *nodes_to_save;
|
|
} else {
|
|
node_refs.reserve(nodes.size());
|
|
for (auto ref = nodes.first_ref(); ref != InvalidNodeRef; ref = nodes.next_ref(ref))
|
|
node_refs.push_back(ref);
|
|
}
|
|
}
|
|
|
|
// [EJ-10082019] do not save instantiated nodes
|
|
node_refs.erase(std::remove_if(std::begin(node_refs), std::end(node_refs),
|
|
[&](const NodeRef &ref) {
|
|
if (const auto *node_ = GetNode_(ref))
|
|
if (node_->flags & NF_Instantiated)
|
|
return true;
|
|
return false;
|
|
}),
|
|
std::end(node_refs));
|
|
|
|
//
|
|
std::array<std::set<ComponentRef>, 5> used_component_refs;
|
|
std::set<ComponentRef> used_script_refs, used_instance_refs;
|
|
|
|
if (save_flags & LSSF_Nodes)
|
|
for (const auto ref : node_refs)
|
|
if (const auto *node_ = GetNode_(ref)) {
|
|
if (transforms.is_valid(node_->components[NCI_Transform]))
|
|
used_component_refs[NCI_Transform].insert(node_->components[NCI_Transform]);
|
|
if (cameras.is_valid(node_->components[NCI_Camera]))
|
|
used_component_refs[NCI_Camera].insert(node_->components[NCI_Camera]);
|
|
if (objects.is_valid(node_->components[NCI_Object]))
|
|
used_component_refs[NCI_Object].insert(node_->components[NCI_Object]);
|
|
if (lights.is_valid(node_->components[NCI_Light]))
|
|
used_component_refs[NCI_Light].insert(node_->components[NCI_Light]);
|
|
if (rigid_bodies.is_valid(node_->components[NCI_RigidBody]))
|
|
used_component_refs[NCI_RigidBody].insert(node_->components[NCI_RigidBody]);
|
|
|
|
{
|
|
const auto &i = node_scripts.find(ref);
|
|
if (i != std::end(node_scripts))
|
|
for (const auto script_ref : i->second)
|
|
used_script_refs.insert(script_ref);
|
|
}
|
|
|
|
{
|
|
const auto &i = node_instance.find(ref);
|
|
if (i != std::end(node_instance))
|
|
used_instance_refs.insert(i->second);
|
|
}
|
|
}
|
|
|
|
if (save_flags & LSSF_Scene)
|
|
for (auto ref : scene_scripts)
|
|
used_script_refs.insert(ref); // flag scene scripts as in-use
|
|
|
|
//
|
|
if (!used_component_refs[NCI_Transform].empty()) {
|
|
auto &js_trsf = js["transforms"];
|
|
for (const auto ref : used_component_refs[NCI_Transform]) {
|
|
if (transforms.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&transforms[ref.idx], js_comp);
|
|
js_trsf.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_component_refs[NCI_Camera].empty()) {
|
|
auto &js_cams = js["cameras"];
|
|
for (const auto ref : used_component_refs[NCI_Camera]) {
|
|
if (cameras.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&cameras[ref.idx], js_comp);
|
|
js_cams.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_component_refs[NCI_Object].empty()) {
|
|
auto &js_objs = js["objects"];
|
|
for (const auto ref : used_component_refs[NCI_Object]) {
|
|
if (objects.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&objects[ref.idx], js_comp, resources);
|
|
js_objs.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_component_refs[NCI_Light].empty()) {
|
|
auto &js_lgts = js["lights"];
|
|
for (const auto ref : used_component_refs[NCI_Light]) {
|
|
if (lights.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&lights[ref.idx], js_comp);
|
|
js_lgts.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_component_refs[NCI_RigidBody].empty()) {
|
|
auto &js_bodies = js["rigid_bodies"];
|
|
for (const auto ref : used_component_refs[NCI_RigidBody]) {
|
|
if (rigid_bodies.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&rigid_bodies[ref.idx], js_comp);
|
|
js_bodies.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_script_refs.empty()) {
|
|
auto &js_scripts = js["scripts"];
|
|
for (const auto ref : used_script_refs) {
|
|
if (scripts.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&scripts[ref.idx], js_comp);
|
|
js_scripts.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!used_instance_refs.empty()) {
|
|
auto &js_inss = js["instances"];
|
|
for (const auto ref : used_instance_refs) {
|
|
if (instances.is_valid(ref)) {
|
|
json js_comp;
|
|
SaveComponent(&instances[ref.idx], js_comp);
|
|
js_inss.push_back(js_comp);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (save_flags & LSSF_Nodes) {
|
|
auto &js_nodes = js["nodes"];
|
|
|
|
for (const auto ref : node_refs)
|
|
if (const auto *node_ = GetNode_(ref)) {
|
|
json js_node;
|
|
|
|
js_node["idx"] = ref;
|
|
js_node["name"] = node_->name;
|
|
js_node["disabled"] = node_->flags & NF_Disabled ? true : false;
|
|
|
|
std::array<uint32_t, 5> idxs = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
|
|
|
|
if (transforms.is_valid(node_->components[NCI_Transform])) {
|
|
const auto i = used_component_refs[NCI_Transform].find(node_->components[NCI_Transform]);
|
|
idxs[NCI_Transform] = numeric_cast<uint32_t>(std::distance(std::begin(used_component_refs[NCI_Transform]), i));
|
|
}
|
|
|
|
if (cameras.is_valid(node_->components[NCI_Camera])) {
|
|
const auto i = used_component_refs[NCI_Camera].find(node_->components[NCI_Camera]);
|
|
idxs[NCI_Camera] = numeric_cast<uint32_t>(std::distance(std::begin(used_component_refs[NCI_Camera]), i));
|
|
}
|
|
|
|
if (objects.is_valid(node_->components[NCI_Object])) {
|
|
const auto i = used_component_refs[NCI_Object].find(node_->components[NCI_Object]);
|
|
idxs[NCI_Object] = numeric_cast<uint32_t>(std::distance(std::begin(used_component_refs[NCI_Object]), i));
|
|
}
|
|
|
|
if (lights.is_valid(node_->components[NCI_Light])) {
|
|
const auto i = used_component_refs[NCI_Light].find(node_->components[NCI_Light]);
|
|
idxs[NCI_Light] = numeric_cast<uint32_t>(std::distance(std::begin(used_component_refs[NCI_Light]), i));
|
|
}
|
|
|
|
if (rigid_bodies.is_valid(node_->components[NCI_RigidBody])) {
|
|
const auto i = used_component_refs[NCI_RigidBody].find(node_->components[NCI_RigidBody]);
|
|
idxs[NCI_RigidBody] = numeric_cast<uint32_t>(std::distance(std::begin(used_component_refs[NCI_RigidBody]), i));
|
|
}
|
|
|
|
js_node["components"] = idxs;
|
|
|
|
{
|
|
const auto &c = node_scripts.find(ref);
|
|
|
|
if (c != std::end(node_scripts)) {
|
|
auto &js_node_scripts = js_node["scripts"];
|
|
|
|
for (const auto script_ref : c->second) {
|
|
const auto i = used_script_refs.find(script_ref);
|
|
|
|
json script;
|
|
script["idx"] = std::distance(std::begin(used_script_refs), i);
|
|
|
|
js_node_scripts.push_back(script);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto &c = node_instance.find(ref);
|
|
if (c != std::end(node_instance)) {
|
|
const auto i = used_instance_refs.find(c->second);
|
|
js_node["instance"] = std::distance(std::begin(used_instance_refs), i);
|
|
}
|
|
}
|
|
|
|
js_nodes.push_back(js_node);
|
|
}
|
|
}
|
|
|
|
if (save_flags & LSSF_Scene) {
|
|
auto &env = js["environment"];
|
|
|
|
if (save_flags & LSSF_Nodes)
|
|
env["current_camera"] = current_camera;
|
|
|
|
env["ambient"] = environment.ambient;
|
|
env["fog_near"] = environment.fog_near;
|
|
env["fog_far"] = environment.fog_far;
|
|
env["fog_color"] = environment.fog_color;
|
|
|
|
if (environment.irradiance_map != InvalidTextureRef)
|
|
env["irradiance_map"] = resources.textures.GetName(environment.irradiance_map);
|
|
if (environment.radiance_map != InvalidTextureRef)
|
|
env["radiance_map"] = resources.textures.GetName(environment.radiance_map);
|
|
if (environment.brdf_map != InvalidTextureRef)
|
|
env["brdf_map"] = resources.textures.GetName(environment.brdf_map);
|
|
|
|
auto &cvs = js["canvas"];
|
|
|
|
cvs["clear_z"] = canvas.clear_z;
|
|
cvs["clear_color"] = canvas.clear_color;
|
|
cvs["color"] = canvas.color;
|
|
}
|
|
|
|
if (save_flags & LSSF_Anims) {
|
|
{
|
|
json anims_js;
|
|
|
|
for (auto ref = anims.first_ref(); ref != InvalidAnimRef; ref = anims.next_ref(ref)) {
|
|
const auto &anim = anims[ref.idx];
|
|
|
|
if (anim.flags & AF_Instantiated)
|
|
continue;
|
|
|
|
json anim_js = {{"idx", ref.idx}};
|
|
SaveAnimToJson(anim_js["anim"], anim);
|
|
|
|
anims_js.push_back(std::move(anim_js));
|
|
}
|
|
|
|
if (!anims_js.empty())
|
|
js["anims"] = std::move(anims_js);
|
|
}
|
|
|
|
{
|
|
json scene_anims_js;
|
|
|
|
for (auto ref = scene_anims.first_ref(); ref != InvalidAnimRef; ref = scene_anims.next_ref(ref)) {
|
|
const auto &scene_anim = scene_anims[ref.idx];
|
|
|
|
if (scene_anim.flags & SAF_Instantiated)
|
|
continue;
|
|
|
|
json scene_anim_js = {
|
|
{"name", scene_anim.name},
|
|
{"t_start", scene_anim.t_start},
|
|
{"t_end", scene_anim.t_end},
|
|
{"anim", scene_anim.scene_anim},
|
|
{"frame_duration", scene_anim.frame_duration},
|
|
};
|
|
|
|
{
|
|
auto &node_anims_js = scene_anim_js["node_anims"];
|
|
|
|
for (const auto &node_anim : scene_anim.node_anims)
|
|
node_anims_js.push_back({
|
|
{"node", node_anim.node.idx},
|
|
{"anim", node_anim.anim.idx},
|
|
});
|
|
}
|
|
|
|
scene_anims_js.push_back(std::move(scene_anim_js));
|
|
}
|
|
|
|
if (!scene_anims_js.empty())
|
|
js["scene_anims"] = std::move(scene_anims_js);
|
|
}
|
|
}
|
|
|
|
if (save_flags & LSSF_KeyValues) {
|
|
auto &kv = js["key_values"];
|
|
for (auto i : key_values)
|
|
kv[i.first] = i.second;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Scene::Load_json(const json &js, const char *name, const Reader &deps_ir, const ReadProvider &deps_ip, PipelineResources &resources,
|
|
const PipelineInfo &pipeline, LoadSceneContext &ctx, uint32_t load_flags) {
|
|
if (js.empty()) {
|
|
error(format("Cannot load scene '%1', empty JSON").arg(name));
|
|
return false;
|
|
}
|
|
|
|
const auto t_start = time_now();
|
|
|
|
//
|
|
std::vector<ComponentRef> transform_refs;
|
|
{
|
|
const auto &i = js.find("transforms");
|
|
if (i != std::end(js)) {
|
|
const auto transform_count = i->size();
|
|
transform_refs.resize(transform_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = transform_refs[n++] = CreateTransform().ref;
|
|
LoadComponent(&transforms[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> camera_refs;
|
|
{
|
|
const auto &i = js.find("cameras");
|
|
if (i != std::end(js)) {
|
|
const auto camera_count = i->size();
|
|
camera_refs.resize(camera_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = camera_refs[n++] = CreateCamera().ref;
|
|
LoadComponent(&cameras[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> object_refs;
|
|
{
|
|
const auto &i = js.find("objects");
|
|
if (i != std::end(js)) {
|
|
const auto object_count = i->size();
|
|
object_refs.resize(object_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = object_refs[n++] = CreateObject().ref;
|
|
LoadComponent(
|
|
&objects[ref.idx], j, deps_ir, deps_ip, resources, pipeline, load_flags & LSSF_QueueTextureLoads, load_flags & LSSF_DoNotLoadResources);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> light_refs;
|
|
{
|
|
const auto &i = js.find("lights");
|
|
if (i != std::end(js)) {
|
|
const auto light_count = i->size();
|
|
light_refs.resize(light_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = light_refs[n++] = CreateLight().ref;
|
|
LoadComponent(&lights[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> rigid_body_refs;
|
|
{
|
|
const auto &i = js.find("rigid_bodies");
|
|
if (i != std::end(js)) {
|
|
const auto rigid_body_count = i->size();
|
|
rigid_body_refs.resize(rigid_body_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = rigid_body_refs[n++] = CreateRigidBody().ref;
|
|
LoadComponent(&rigid_bodies[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> script_refs;
|
|
{
|
|
const auto &i = js.find("scripts");
|
|
if (i != std::end(js)) {
|
|
const auto scripts_count = i->size();
|
|
script_refs.resize(scripts_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = script_refs[n++] = CreateScript().ref;
|
|
LoadComponent(&scripts[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ComponentRef> instance_refs;
|
|
{
|
|
const auto &i = js.find("instances");
|
|
if (i != std::end(js)) {
|
|
const auto instance_count = i->size();
|
|
instance_refs.resize(instance_count);
|
|
|
|
int n = 0;
|
|
for (const auto &j : *i) {
|
|
const auto ref = instance_refs[n++] = CreateInstance().ref;
|
|
LoadComponent(&instances[ref.idx], j);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
std::vector<NodeRef> nodes_to_disable;
|
|
|
|
const auto &js_nodes = js.find("nodes");
|
|
|
|
if (js_nodes != std::end(js)) {
|
|
std::vector<NodeRef> node_with_instance_to_setup;
|
|
node_with_instance_to_setup.reserve(64);
|
|
|
|
const auto node_count = js_nodes->size();
|
|
for (const auto &js_node : *js_nodes) {
|
|
auto node = CreateNode();
|
|
auto node_ = nodes[node.ref.idx];
|
|
|
|
ctx.node_refs[js_node["idx"].get<uint32_t>()] = node.ref;
|
|
ctx.view.nodes.push_back(node.ref);
|
|
|
|
node.SetName(js_node["name"].get<std::string>());
|
|
|
|
{
|
|
const auto &i = js_node.find("disabled");
|
|
if ((i != std::end(js_node)) && (i->get<bool>() == true))
|
|
nodes_to_disable.push_back(node.ref);
|
|
}
|
|
|
|
{
|
|
const auto &js_node_components = js_node["components"];
|
|
|
|
const auto transform_idx = js_node_components[NCI_Transform].get<ComponentRef>().idx;
|
|
if (transform_idx != 0xffffffff)
|
|
nodes[node.ref.idx].components[NCI_Transform] = transform_refs[transform_idx];
|
|
|
|
const auto camera_idx = js_node_components[NCI_Camera].get<ComponentRef>().idx;
|
|
if (camera_idx != 0xffffffff)
|
|
nodes[node.ref.idx].components[NCI_Camera] = camera_refs[camera_idx];
|
|
|
|
const auto object_idx = js_node_components[NCI_Object].get<ComponentRef>().idx;
|
|
if (object_idx != 0xffffffff)
|
|
nodes[node.ref.idx].components[NCI_Object] = object_refs[object_idx];
|
|
|
|
const auto light_idx = js_node_components[NCI_Light].get<ComponentRef>().idx;
|
|
if (light_idx != 0xffffffff)
|
|
nodes[node.ref.idx].components[NCI_Light] = light_refs[light_idx];
|
|
|
|
const auto rigid_body_idx = js_node_components[NCI_RigidBody].get<ComponentRef>().idx;
|
|
if (rigid_body_idx != 0xffffffff)
|
|
nodes[node.ref.idx].components[NCI_RigidBody] = rigid_body_refs[rigid_body_idx];
|
|
}
|
|
|
|
{
|
|
const auto &js_scripts = js_node.find("scripts");
|
|
|
|
if (js_scripts != std::end(js_node)) {
|
|
const auto node_script_count = js_scripts->size();
|
|
node_scripts[node.ref].reserve(node_script_count);
|
|
for (auto &js_script : *js_scripts) {
|
|
const auto script_idx = js_script["idx"].get<ComponentRef>().idx;
|
|
|
|
if (script_idx != 0xffffffff) {
|
|
const auto script_ref = script_refs[script_idx];
|
|
node_scripts[node.ref].push_back(script_ref);
|
|
} else {
|
|
node_scripts[node.ref].push_back(InvalidComponentRef);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto &js_node_instance = js_node.find("instance");
|
|
if (js_node_instance != std::end(js_node)) {
|
|
const auto instance_idx = js_node_instance->get<ComponentRef>().idx;
|
|
if (instance_idx != 0xffffffff) {
|
|
node_instance[node.ref] = instance_refs[instance_idx];
|
|
node_with_instance_to_setup.push_back(node.ref);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// setup instances
|
|
if (!(load_flags & LSSF_DoNotLoadResources))
|
|
for (const auto ref : node_with_instance_to_setup) {
|
|
NodeSetupInstance(ref, deps_ir, deps_ip, resources, pipeline, LSSF_AllNodeFeatures, ctx.recursion_level + 1);
|
|
NodeStartOnInstantiateAnim(ref);
|
|
}
|
|
|
|
// fix parent references
|
|
for (const auto ref : transform_refs) {
|
|
auto &c = transforms[ref.idx];
|
|
if (c.parent != InvalidNodeRef) {
|
|
const auto &i = ctx.node_refs.find(c.parent.idx);
|
|
c.parent = i != std::end(ctx.node_refs) ? i->second : InvalidNodeRef;
|
|
}
|
|
}
|
|
|
|
// fix bone references
|
|
for (const auto ref : object_refs) {
|
|
auto &c = objects[ref.idx];
|
|
for (auto &ref : c.bones)
|
|
if (ref != InvalidNodeRef) {
|
|
const auto &i = ctx.node_refs.find(ref.idx);
|
|
ref = i != std::end(ctx.node_refs) ? i->second : InvalidNodeRef;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (load_flags & LSSF_Scene) {
|
|
{
|
|
const auto &js_env = js.find("environment");
|
|
|
|
if (js_env != std::end(js)) {
|
|
const auto &js_current_camera = js_env->find("current_camera");
|
|
if (js_current_camera != std::end(*js_env)) {
|
|
const auto current_camera_idx = js_current_camera->get<NodeRef>().idx;
|
|
current_camera = ctx.node_refs[current_camera_idx];
|
|
}
|
|
|
|
environment.ambient = (*js_env)["ambient"];
|
|
environment.fog_near = (*js_env)["fog_near"];
|
|
environment.fog_far = (*js_env)["fog_far"];
|
|
environment.fog_color = (*js_env)["fog_color"];
|
|
|
|
{
|
|
auto i = js_env->find("irradiance_map");
|
|
if (i != std::end(*js_env)) {
|
|
if (load_flags & LSSF_DoNotLoadResources) {
|
|
environment.irradiance_map = resources.textures.Add(i->get<std::string>().c_str(), {});
|
|
} else {
|
|
|
|
if (load_flags & LSSF_QueueTextureLoads)
|
|
environment.irradiance_map = QueueLoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
else
|
|
environment.irradiance_map = LoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
}
|
|
}
|
|
|
|
i = js_env->find("radiance_map");
|
|
if (i != std::end(*js_env)) {
|
|
if (load_flags & LSSF_DoNotLoadResources) {
|
|
environment.radiance_map = resources.textures.Add(i->get<std::string>().c_str(), {});
|
|
} else {
|
|
|
|
if (load_flags & LSSF_QueueTextureLoads)
|
|
environment.radiance_map = QueueLoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
else
|
|
environment.radiance_map = LoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
}
|
|
}
|
|
|
|
i = js_env->find("brdf_map");
|
|
if (i != std::end(*js_env)) {
|
|
if (load_flags & LSSF_DoNotLoadResources) {
|
|
environment.brdf_map = resources.textures.Add(i->get<std::string>().c_str(), {});
|
|
} else {
|
|
if (load_flags & LSSF_QueueTextureLoads)
|
|
environment.brdf_map = QueueLoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
else
|
|
environment.brdf_map = LoadTexture(deps_ir, deps_ip, i->get<std::string>().c_str(), BGFX_SAMPLER_NONE, resources);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto &js_cvs = js.find("canvas");
|
|
|
|
if (js_cvs != std::end(js)) {
|
|
canvas.clear_z = (*js_cvs)["clear_z"];
|
|
canvas.clear_color = (*js_cvs)["clear_color"];
|
|
canvas.color = (*js_cvs)["color"];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (load_flags & LSSF_Anims) {
|
|
std::map<uint32_t, AnimRef> anim_refs;
|
|
|
|
{
|
|
const auto &js_anims = js.find("anims");
|
|
|
|
if (js_anims != std::end(js))
|
|
for (const auto &js_anim : *js_anims) {
|
|
Anim anim;
|
|
LoadAnimFromJson(js_anim["anim"], anim);
|
|
|
|
const auto anim_ref = AddAnim(anim);
|
|
ctx.view.anims.push_back(anim_ref);
|
|
|
|
const uint32_t idx = js_anim["idx"];
|
|
anim_refs[idx] = anim_ref;
|
|
}
|
|
}
|
|
|
|
{
|
|
const auto &js_scene_anims = js.find("scene_anims");
|
|
|
|
if (js_scene_anims != std::end(js)) {
|
|
for (const auto &js_scene_anim : *js_scene_anims) {
|
|
SceneAnim scene_anim;
|
|
|
|
js_scene_anim.at("name").get_to(scene_anim.name);
|
|
scene_anim.t_start = js_scene_anim.at("t_start");
|
|
scene_anim.t_end = js_scene_anim.at("t_end");
|
|
scene_anim.scene_anim = js_scene_anim.at("anim");
|
|
scene_anim.frame_duration = js_scene_anim.at("frame_duration");
|
|
|
|
const auto &i_scene_anim = anim_refs.find(scene_anim.scene_anim.idx);
|
|
if (i_scene_anim != std::end(anim_refs))
|
|
scene_anim.scene_anim = i_scene_anim->second;
|
|
|
|
const auto &js_node_anims = js_scene_anim.find("node_anims");
|
|
if (js_node_anims != std::end(js_scene_anim))
|
|
for (const auto js_node_anim : *js_node_anims) {
|
|
const uint32_t node_idx = js_node_anim["node"];
|
|
const uint32_t anim_idx = js_node_anim["anim"];
|
|
|
|
const auto &i_node_ref = ctx.node_refs.find(node_idx); // remap node
|
|
const auto &i_anim_ref = anim_refs.find(anim_idx); // remap anim
|
|
|
|
if (i_node_ref != std::end(ctx.node_refs) && i_anim_ref != std::end(anim_refs))
|
|
scene_anim.node_anims.push_back({i_node_ref->second, i_anim_ref->second});
|
|
}
|
|
|
|
const auto scene_anim_ref = AddSceneAnim(scene_anim);
|
|
ctx.view.scene_anims.push_back(scene_anim_ref);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (load_flags & LSSF_KeyValues) {
|
|
const auto &js_key_values = js.find("key_values");
|
|
|
|
if (js_key_values != std::end(js))
|
|
for (auto i : js_key_values->items())
|
|
key_values[i.key()] = i.value().get<std::string>();
|
|
}
|
|
|
|
//
|
|
for (const auto &ref : nodes_to_disable)
|
|
DisableNode(ref);
|
|
|
|
//
|
|
ReadyWorldMatrices();
|
|
ComputeWorldMatrices();
|
|
|
|
//
|
|
debug(format("Load scene '%1' took %2 ms").arg(name).arg(time_to_ms(time_now() - t_start)));
|
|
return true;
|
|
}
|
|
|
|
} // namespace hg
|