2#ifndef LIBSBX_SCENES_SCENE_GRAPH_HPP_
3#define LIBSBX_SCENES_SCENE_GRAPH_HPP_
6#include <unordered_map>
8#include <easy/profiler.h>
10#include <libsbx/utility/iterator.hpp>
11#include <libsbx/utility/logger.hpp>
13#include <libsbx/memory/tracking_allocator.hpp>
15#include <libsbx/ecs/registry.hpp>
16#include <libsbx/ecs/entity.hpp>
18#include <libsbx/math/uuid.hpp>
19#include <libsbx/math/vector3.hpp>
20#include <libsbx/math/quaternion.hpp>
21#include <libsbx/math/matrix4x4.hpp>
23#include <libsbx/scenes/node.hpp>
24#include <libsbx/scenes/components/id.hpp>
25#include <libsbx/scenes/components/tag.hpp>
26#include <libsbx/scenes/components/relationship.hpp>
27#include <libsbx/scenes/components/transform.hpp>
28#include <libsbx/scenes/components/global_transform.hpp>
30namespace sbx::scenes {
38 template<
typename... Exclude>
39 inline static constexpr auto query_filter = ecs::exclude<Exclude...>;
43 _root{_registry.create()} {
44 const auto& root_id = _registry.emplace<
scenes::id>(_root);
46 _nodes.insert({root_id, _root});
54 auto root()
const -> scenes::node {
58 auto node_count()
const -> std::size_t {
62 auto is_valid(
const scenes::node
node)
const ->
bool {
63 return _registry.is_valid(
node);
66 auto find_node(
const scenes::id&
id) -> scenes::node {
67 if (
auto entry = _nodes.find(
id); entry != _nodes.end()) {
71 return scenes::node::null;
79 auto node = _registry.create();
95 auto destroy_node(
const scenes::node
node) ->
void {
102 auto stack = std::vector<std::pair<scenes::node, bool>>{};
105 stack.emplace_back(
node,
false);
107 while (!stack.empty()) {
108 auto [current_node, visited] = stack.back();
111 if (current_node == scenes::node::null) {
116 stack.emplace_back(current_node,
true);
120 for (
auto child : current_relationship.children()) {
121 if (child != node::null) {
122 stack.emplace_back(child,
false);
126 const auto&
id = _registry.get<
scenes::id>(current_node);
129 _registry.destroy(current_node);
134 auto make_child_of(
const scenes::node
node,
const scenes::node parent) ->
void {
135 if (
node == parent) {
141 if (node_relationship.parent() == parent) {
147 if (node_relationship.parent() != scenes::node::null) {
148 auto& old_parent_relationship = _registry.get<
scenes::relationship>(node_relationship.parent());
150 old_parent_relationship.remove_child(
node);
153 node_relationship.set_parent(parent);
154 new_parent_relationship.add_child(
node);
157 auto reassign_node_id(
const scenes::node
node,
const math::uuid new_id) ->
void {
160 _nodes.insert({new_id,
node});
163 template<
typename Type,
typename... Other,
typename... Exclude>
165 return _registry.view<Type, Other...>(ecs::exclude<Exclude...>);
168 template<
typename Type,
typename... Other,
typename... Exclude>
170 return _registry.view<Type, Other...>(ecs::exclude<Exclude...>);
173 template<
typename Type,
typename Compare,
typename Sort =
utility::std_sort,
typename... Args>
174 auto sort(Compare compare, Sort sort = Sort{}, Args&&... args) ->
void {
175 _registry.sort<Type>(std::move(compare), std::move(sort), std::forward<Args>(args)...);
178 template<
typename Component>
179 auto has_component(
const scenes::node
node)
const ->
bool {
180 return _registry.all_of<Component>(
node);
183 template<
typename Component,
typename... Args>
184 auto add_component(
const scenes::node
node, Args&&... args) ->
decltype(
auto) {
185 return _registry.emplace<Component>(
node, std::forward<Args>(args)...);
188 template<
typename Component,
typename... Args>
189 auto add_or_update_component(
const scenes::node
node, Args&&... args) ->
decltype(
auto) {
190 return _registry.emplace_or_replace<Component>(
node, std::forward<Args>(args)...);
193 template<
typename Component>
194 auto get_component(
const scenes::node
node)
const ->
const Component& {
195 return _registry.get<Component>(
node);
198 template<
typename Component>
199 auto get_component(
const scenes::node
node) -> Component& {
200 return _registry.get<Component>(
node);
203 template<
typename Component,
typename... Args>
204 auto get_or_add_component(
const scenes::node
node, Args&&... args) -> Component& {
205 return _registry.get_or_emplace<Component>(
node, std::forward<Args>(args)...);
208 template<
typename Component>
210 return _registry.try_get<Component>(
node);
222 EASY_BLOCK(
"scene_graph::world_transform");
223 return _ensure_world(
node).model;
227 EASY_BLOCK(
"scene_graph::world_normal");
228 return _ensure_world(
node).normal;
232 EASY_BLOCK(
"scene_graph::parent_transform");
240 return math::matrix4x4::identity;
244 EASY_BLOCK(
"scene_graph::world_position");
249 EASY_BLOCK(
"scene_graph::world_rotation");
254 EASY_BLOCK(
"scene_graph::world_scale");
256 const auto world = world_transform(
node);
268 auto chain = utility::make_array<scenes::node, 32u>(scenes::node::null);
269 auto chain_size = std::uint32_t{0};
271 for (
auto current =
node; current != scenes::node::null;) {
272 chain[chain_size++] = current;
279 auto parent_world = math::matrix4x4::identity;
280 auto parent_world_version = std::uint64_t{0};
282 for (
auto i = chain_size - 1u; (i >= 0u && i < chain_size); --i) {
283 const auto current = chain[i];
288 if (world.local_seen != local.version() || world.parent_seen != parent_world_version) {
289 world.model = parent_world * local.local_transform();
290 world.normal = math::matrix4x4::transposed(math::matrix4x4::inverted(world.model));
291 world.local_seen = local.version();
292 world.parent_seen = parent_world_version;
297 parent_world = world.model;
298 parent_world_version = world.version;
306 std::unordered_map<math::uuid, scenes::node> _nodes;
Definition: matrix4x4.hpp:26
Definition: quaternion.hpp:25
Definition: vector3.hpp:23
A non-owning pointer that can be used to observe the value of a pointer.
Definition: observer_ptr.hpp:29
Definition: relationship.hpp:14
Definition: scene_graph.hpp:32
Definition: algorithm.hpp:13