Skip to content

Commit

Permalink
gh-35: impl scene tree loading and instantiation from yaml file
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorOrachyov committed Aug 10, 2023
1 parent b66b7c1 commit 39423c0
Show file tree
Hide file tree
Showing 19 changed files with 337 additions and 229 deletions.
5 changes: 5 additions & 0 deletions engine/core/uuid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ namespace wmoge {
UUID() = default;
UUID(std::uint64_t value);

[[nodiscard]] bool is_null() const { return m_value == 0; }
[[nodiscard]] bool is_not_null() const { return m_value != 0; }

operator bool() const { return is_not_null(); }

[[nodiscard]] std::string to_str() const;

[[nodiscard]] std::uint64_t& value() { return m_value; }
Expand Down
13 changes: 13 additions & 0 deletions engine/io/yaml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#define WMOGE_YAML_HPP

#include "core/log.hpp"
#include "core/ref.hpp"
#include "core/string_id.hpp"

#include <magic_enum.hpp>
Expand Down Expand Up @@ -207,6 +208,12 @@ namespace wmoge {
WG_YAML_READ(node, wrapper.value());
return true;
}
template<typename T>
bool yaml_read(const YamlConstNodeRef& node, Ref<T>& ref) {
assert(ref);
WG_YAML_READ(node, *ref);
return true;
}

template<typename T, std::size_t S>
bool yaml_write(YamlNodeRef node, const std::array<T, S>& array) {
Expand Down Expand Up @@ -252,6 +259,12 @@ namespace wmoge {
WG_YAML_WRITE(node, wrapper.value());
return true;
}
template<typename T>
bool yaml_write(YamlNodeRef node, const Ref<T>& ref) {
assert(ref);
WG_YAML_WRITE(node, *ref);
return true;
}

}// namespace wmoge

Expand Down
88 changes: 22 additions & 66 deletions engine/resource/scene_packed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,112 +30,68 @@
#include "core/class.hpp"
#include "core/engine.hpp"
#include "core/log.hpp"
#include "core/task.hpp"
#include "core/timer.hpp"
#include "debug/profiler.hpp"
#include "platform/file_system.hpp"
#include "resource/resource_manager.hpp"
#include "scene/scene.hpp"
#include "scene/scene_manager.hpp"
#include "scene/scene_tree_visitors.hpp"

namespace wmoge {

bool ScenePacked::load_from_yaml(const YamlConstNodeRef& node) {
WG_AUTO_PROFILE_RESOURCE("ScenePacked::load_from_import_options");
WG_AUTO_PROFILE_RESOURCE("ScenePacked::load_from_yaml");

if (!Resource::load_from_yaml(node)) {
return false;
}

auto params = node;
SceneTree& tree = m_scene_tree.emplace();
WG_YAML_READ(node, tree);

std::string format;
params["format"] >> format;

std::string file;
params["file"] >> file;

assert(format == "text");

if (format == "text") {
std::vector<std::uint8_t> data;
if (!Engine::instance()->file_system()->read_file(file, data)) {
WG_LOG_ERROR("failed to read file " << file);
return false;
}

m_scene_data_yaml.emplace(yaml_parse(data));
if (m_scene_data_yaml.value().empty()) {
WG_LOG_ERROR("failed to parse file " << file);
return false;
}

return true;
}

WG_LOG_ERROR("unsupported scene format " << format);
return false;
return true;
}
void ScenePacked::copy_to(Resource& copy) {
Resource::copy_to(copy);
auto* scene_packed = dynamic_cast<ScenePacked*>(&copy);
scene_packed->m_scene_data_yaml = m_scene_data_yaml;
auto* scene_packed = dynamic_cast<ScenePacked*>(&copy);
scene_packed->m_scene_tree = m_scene_tree;
}

AsyncResult<Ref<Scene>> ScenePacked::instantiate_async() {
WG_AUTO_PROFILE_RESOURCE("ScenePacked::instantiate_async");

assert(m_scene_data_yaml.has_value());
assert(m_scene_tree.has_value());

if (!m_scene_data_yaml.has_value()) {
if (!m_scene_tree.has_value()) {
WG_LOG_ERROR("cannot instantiate scene from no data");
return AsyncResult<Ref<Scene>>{};
}

auto* resource_manager = Engine::instance()->resource_manager();
auto& file = m_scene_data_yaml.value();
auto scene_async = make_async_op<Ref<Scene>>();
auto deps = file["deps"];
auto scene_packed = Ref<ScenePacked>(this);
AsyncOp<Ref<Scene>> scene_async = make_async_op<Ref<Scene>>();

std::vector<Async> deps_loading;
Task scene_task(get_name(), [self = Ref<ScenePacked>(this), scene_async](TaskContext&) {
Ref<Scene> scene = Engine::instance()->scene_manager()->make_scene(self->get_name());

for (auto it = deps.first_child(); it.valid(); it = it.next_sibling()) {
auto res = SID("");//Yaml::read_sid(it);
auto res_async = resource_manager->load_async(res);

if (res_async.is_null()) {
WG_LOG_ERROR("failed to obtain async load for dep " << res);
return AsyncResult<Ref<Scene>>{};
}

deps_loading.push_back(res_async.as_async());
}

Task scene_task(get_name(), [scene_async, scene_packed](auto&) {
WG_AUTO_PROFILE_RESOURCE("ScenePacked::construct_scene");
SceneTreeVisitorEmitScene visitor(scene);

Timer timer;

timer.start();

auto* scene_manager = Engine::instance()->scene_manager();
auto scene = scene_manager->make_scene(scene_packed->get_name());
if (!self->m_scene_tree.value().visit(visitor)) {
WG_LOG_ERROR("failed to emit ecs scene from scene tree " << self->get_name());
return 1;
}

timer.stop();
WG_LOG_INFO("instantiate ecs scene " << self->get_name() << ", time: " << timer.get_elapsed_sec() << " sec");

WG_LOG_INFO("instantiate scene " << scene_packed->get_name() << ", time: " << timer.get_elapsed_sec() << " sec");
scene_async->set_result(std::move(scene));

return 0;
});

WG_LOG_INFO("total deps to pre-load " << deps_loading.size() << " for " << get_name());

auto scene_task_hnd = scene_task.schedule(Async::join(ArrayView(deps_loading)));

scene_task_hnd.add_on_completion([scene_async](AsyncStatus status, std::optional<int>&) {
if (status == AsyncStatus::Failed) {
scene_async->set_failed();
}
});
scene_task.schedule();

return AsyncResult<Ref<Scene>>(scene_async);
}
Expand Down
3 changes: 2 additions & 1 deletion engine/resource/scene_packed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "io/yaml.hpp"
#include "resource/resource.hpp"
#include "scene/scene.hpp"
#include "scene/scene_tree.hpp"

#include <optional>

Expand Down Expand Up @@ -63,7 +64,7 @@ namespace wmoge {
Ref<Scene> instantiate();

private:
std::optional<YamlTree> m_scene_data_yaml;
std::optional<SceneTree> m_scene_tree;
};

}// namespace wmoge
Expand Down
3 changes: 2 additions & 1 deletion engine/scene/register_classes_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ namespace wmoge {
void register_classes_scene() {
SceneNode::register_class();
SceneNodeFolder::register_class();
SceneNodeTransform::register_class();
SceneNodePrefab::register_class();
SceneNodeEntity::register_class();
SceneNodeComponent::register_class();
SceneNodeTransform::register_class();
SceneNodeCamera::register_class();
}

Expand Down
12 changes: 12 additions & 0 deletions engine/scene/scene_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,23 @@

#include "core/engine.hpp"
#include "debug/profiler.hpp"
#include "ecs/ecs_registry.hpp"
#include "scene/scene_components.hpp"

namespace wmoge {

SceneManager::SceneManager() {
WG_LOG_INFO("init scene manager");

auto* ecs_registry = Engine::instance()->ecs_registry();

ecs_registry->register_component<EcsComponentChildren>();
ecs_registry->register_component<EcsComponentParent>();
ecs_registry->register_component<EcsComponentSceneTransform>();
ecs_registry->register_component<EcsComponentLocalToWorld>();
ecs_registry->register_component<EcsComponentSceneNode>();
ecs_registry->register_component<EcsComponentName>();
ecs_registry->register_component<EcsComponentCamera>();
}

void SceneManager::next(Ref<Scene> scene) {
Expand Down
91 changes: 69 additions & 22 deletions engine/scene/scene_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,6 @@ namespace wmoge {
assert(tree);
}

bool SceneNode::visit(class SceneTreeVisitor& visitor) {
return visitor.visit(*this);
}
EcsArch SceneNode::get_arch() {
return EcsArch{};
}

void SceneNode::set_transform(const TransformEdt& transform) {
m_transform = transform;
on_transformed();
Expand All @@ -71,35 +64,89 @@ namespace wmoge {
m_children.erase(std::find(m_children.begin(), m_children.end(), child));
}

Mat4x4f SceneNode::get_lt() const {
return m_transform.get_transform();
}
Mat4x4f SceneNode::get_lt_inverse() const {
return m_transform.get_inverse_transform();
}
Mat4x4f SceneNode::get_l2w() const {
const Mat4x4f matrix = get_lt();
return m_parent ? m_parent->get_l2w() * matrix : matrix;
}
Mat4x4f SceneNode::get_w2l() const {
const Mat4x4f matrix = get_lt_inverse();
return m_parent ? matrix * m_parent->get_w2l() : matrix;
}

bool SceneNode::on_yaml_read(const YamlConstNodeRef& node) {
WG_YAML_READ_AS(node, "uuid", m_uuid);
WG_YAML_READ_AS(node, "name", m_name);
WG_YAML_READ_AS(node, "transform", m_transform);
WG_YAML_READ_AS_OPT(node, "uuid", m_uuid);
WG_YAML_READ_AS_OPT(node, "name", m_name);
WG_YAML_READ_AS_OPT(node, "transform", m_transform);

if (!m_uuid) {
m_uuid = UUID::generate();
}

if (m_name.empty()) {
m_name = SID(class_ptr()->name().str() + "_" + m_uuid.to_str());
}

if (node.has_child("children")) {
for (auto child_itr = node["children"].first_child(); child_itr.valid(); child_itr = child_itr.next_sibling()) {
StringId class_name;

WG_YAML_READ_AS(child_itr, "class", class_name);

Class* class_ptr = Class::class_ptr(class_name);

if (!class_ptr) {
WG_LOG_ERROR("no such class " << class_name << " to instantiate child of node " << m_name);
return false;
}

Ref<SceneNode> child = class_ptr->instantiate().cast<SceneNode>();

if (!child) {
WG_LOG_ERROR("failed to instantiate child of " << m_name);
return false;
}

assert(m_tree);
child->m_tree = m_tree;

if (!child->on_yaml_read(child_itr)) {
WG_LOG_ERROR("failed to parse child of " << m_name);
return false;
}

m_children.push_back(child);
}
}

return true;
}
bool SceneNode::on_yaml_write(YamlNodeRef node) {
bool SceneNode::on_yaml_write(YamlNodeRef node) const {
WG_YAML_MAP(node);
WG_YAML_WRITE_AS(node, "class", class_ptr()->name());
WG_YAML_WRITE_AS(node, "uuid", m_uuid);
WG_YAML_WRITE_AS(node, "name", m_name);
WG_YAML_WRITE_AS(node, "transform", m_transform);
WG_YAML_WRITE_AS_OPT(node, "children", !m_children.empty(), m_children);

return true;
}

Mat4x4f SceneNode::get_lt() const {
return m_transform.get_transform();
bool SceneNode::on_visit(class SceneTreeVisitor& visitor) {
return visitor.visit(*this);
}
Mat4x4f SceneNode::get_lt_inverse() const {
return m_transform.get_inverse_transform();
void SceneNode::on_ecs_arch_collect(EcsArch&) {
}
Mat4x4f SceneNode::get_l2w() const {
const Mat4x4f matrix = get_lt();
return m_parent ? m_parent->get_l2w() * matrix : matrix;

bool yaml_read(const YamlConstNodeRef& node, SceneNode& scene_node) {
return scene_node.on_yaml_read(node);
}
Mat4x4f SceneNode::get_w2l() const {
const Mat4x4f matrix = get_lt_inverse();
return m_parent ? matrix * m_parent->get_w2l() : matrix;
bool yaml_write(YamlNodeRef node, const SceneNode& scene_node) {
return scene_node.on_yaml_write(node);
}

void SceneNode::register_class() {
Expand Down
Loading

0 comments on commit 39423c0

Please sign in to comment.