- Refactor on component system to support multiple scenes.

- node2d for 2d scenes
This commit is contained in:
2025-09-25 19:30:08 -04:00
parent f636feb4f1
commit 8925b3f2f0
10 changed files with 422 additions and 171 deletions

View File

@@ -92,6 +92,8 @@ add_library(fennec STATIC
# SCENE ================================================================================================================ # SCENE ================================================================================================================
include/fennec/scene/scene.h include/fennec/scene/scene.h
include/fennec/scene/component.h include/fennec/scene/component.h
include/fennec/scene/scene_node.h
include/fennec/scene/node2d.h
# Renderers ============================================================================================================ # Renderers ============================================================================================================
@@ -217,9 +219,10 @@ add_library(fennec STATIC
# langproc ================================================================================================================ # langproc ================================================================================================================
# Strings # Strings
include/fennec/langproc/strings/cstring.h
include/fennec/langproc/strings/locale.h include/fennec/langproc/strings/locale.h
include/fennec/langproc/strings/cstring.h
include/fennec/langproc/strings/string.h include/fennec/langproc/strings/string.h
include/fennec/langproc/strings/format.h
include/fennec/langproc/strings/detail/_ctype.h include/fennec/langproc/strings/detail/_ctype.h
@@ -244,8 +247,6 @@ add_library(fennec STATIC
# EXTRA SOURCES ======================================================================================================== # EXTRA SOURCES ========================================================================================================
${FENNEC_EXTRA_SOURCES} ${FENNEC_EXTRA_SOURCES}
include/fennec/langproc/strings/format.h
include/fennec/scene/components/transform2d.h
) )
add_dependencies(fennec metaprogramming fennec-dependencies) add_dependencies(fennec metaprogramming fennec-dependencies)

View File

@@ -48,7 +48,8 @@ struct object_pool {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using value_t = TypeT; using value_t = TypeT;
using table_t = allocation<value_t, AllocT>; using elem_t = optional<value_t>;
using table_t = dynarray<elem_t, AllocT>;
using freed_t = list<size_t, AllocT>; using freed_t = list<size_t, AllocT>;
@@ -119,7 +120,8 @@ public:
/// \returns a reference to the object with id `i` /// \returns a reference to the object with id `i`
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
return _table[i]; assert(_table[i], "Attempted to access null object.")
return *_table[i];
} }
/// ///
@@ -128,7 +130,8 @@ public:
/// \returns a const-qualified reference to the object with id `i` /// \returns a const-qualified reference to the object with id `i`
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
return _table[i]; assert(_table[i], "Attempted to access null object.")
return *_table[i];
} }
/// @} /// @}
@@ -169,7 +172,7 @@ public:
/// \brief Erase an object from the pool /// \brief Erase an object from the pool
/// \param i The id of the object /// \param i The id of the object
constexpr void erase(size_t i) { constexpr void erase(size_t i) {
fennec::destruct(&_table[i]); _table[i] = nullopt;
_freed.push_back(i); _freed.push_back(i);
--_size; --_size;
} }
@@ -177,8 +180,11 @@ public:
/// ///
/// \brief Clear the object pool /// \brief Clear the object pool
constexpr void clear() { constexpr void clear() {
dynarray<bool> free(capacity(), false); for (auto& it : _table) {
it = nullopt;
}
_size = 0; _size = 0;
_freed.clear();
} }
/// @} /// @}
@@ -201,10 +207,10 @@ private:
template<typename...ArgsT> template<typename...ArgsT>
size_t _insert(ArgsT&&...args) { size_t _insert(ArgsT&&...args) {
size_t i = _next_free(); size_t i = _next_free();
if (i >= _table.capacity()) { if (i >= _table.size()) {
_table.creallocate(fennec::max(_table.size() * 2, size_t(8))); _table.resize(fennec::max(_table.size() * 2, size_t(8)));
} }
fennec::construct(&_table[i], fennec::forward<ArgsT>(args)...); _table[i].emplace(fennec::forward<ArgsT>(args)...);
return i; return i;
} }
}; };

View File

@@ -58,9 +58,9 @@ public:
protected: protected:
struct node { struct node {
optional<value_t> value; value_t value;
size_t parent, child, prev, next; size_t parent, child, prev, next;
size_t depth, num_children; size_t depth, num_children;
constexpr node() constexpr node()
: value(nullopt) : value(nullopt)
@@ -315,25 +315,15 @@ public:
/// ///
/// \param i The id of the node to access /// \param i The id of the node to access
/// \returns A reference to the value of the node wrapped in an optional /// \returns A reference to the value of the node wrapped in an optional
constexpr value_t* operator[](size_t i) { constexpr value_t& operator[](size_t i) {
auto& it = _table[i].value; return _table[i].value;
if (it) {
return &*_table[i].value;
} else {
return nullptr;
}
} }
/// ///
/// \param i The id of the node to access /// \param i The id of the node to access
/// \returns A const-qualified reference to the value of the node wrapped in an optional /// \returns A const-qualified reference to the value of the node wrapped in an optional
constexpr const value_t* operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
const auto& it = _table[i].value; return _table[i].value;
if (it) {
return &*_table[i].value;
} else {
return nullptr;
}
} }
@@ -420,7 +410,7 @@ public:
while (i != npos) { while (i != npos) {
uint8_t mode = traversal_control_continue; uint8_t mode = traversal_control_continue;
if (_table[i].value) { if (_table[i].value) {
mode = visit(*_table[i].value, i); mode = visit(_table[i].value, i);
} }
if (mode == traversal_control_break) { if (mode == traversal_control_break) {
break; break;

View File

@@ -32,6 +32,8 @@
#define FENNEC_LANGPROC_FORMAT_TOKENIZER_H #define FENNEC_LANGPROC_FORMAT_TOKENIZER_H
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/containers/map.h>
#include <fennec/containers/priority_queue.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
// //
@@ -55,7 +57,7 @@ namespace fennec
{ {
struct escape_sequence { struct escape_sequence {
virtual size_t operator[](const std::string& str, size_t i) = 0; virtual size_t operator[](const string& str, size_t i) = 0;
}; };
struct tokenizer { struct tokenizer {
@@ -91,12 +93,12 @@ private:
list<token> res; list<token> res;
priority_queue<pair<size_t, uint8_t>> idx; priority_queue<pair<size_t, uint8_t>> idx;
for (size_t i = 0; i < line.size(); ++i) { for (char c : delimiter) {
size_t i = 0;
for (char c : delimiter) { while (i != line.size()) {
idx.emplace() size_t n = line.find(c, i);
// TODO
} }
} }
return res; return res;

View File

@@ -19,6 +19,7 @@
#ifndef FENNEC_LANGPROC_IO_PATH_H #ifndef FENNEC_LANGPROC_IO_PATH_H
#define FENNEC_LANGPROC_IO_PATH_H #define FENNEC_LANGPROC_IO_PATH_H
#include <fennec/langproc/filesystem/path.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
namespace fennec namespace fennec
@@ -32,6 +33,12 @@ namespace fennec
struct path struct path
{ {
public: public:
// Definitions =========================================================================================================
class iterator;
friend iterator;
// Static Functions ==================================================================================================== // Static Functions ====================================================================================================
/// \brief Get the current working directory /// \brief Get the current working directory
@@ -154,6 +161,11 @@ public:
return _str == p._str; return _str == p._str;
} }
string filename() const {
size_t i = _str.rfind('/');
return _str.substring(i + 1);
}
const string& str() const { return _str; } const string& str() const { return _str; }
const char* cstr() const { return _str.cstr(); } const char* cstr() const { return _str.cstr(); }
@@ -238,6 +250,81 @@ public:
return working; return working;
} }
// Iterator ============================================================================================================
iterator begin() const {
return iterator(this, 0);
}
iterator end() const {
return iterator(this, _str.size());
}
class iterator {
public:
constexpr iterator(const path* path, size_t p)
: _str(&path->_str)
, _pos(p) {
// Handle end()
if (p == _str->size()) {
return;
}
// Handle rooted paths
#ifdef FENNEC_PLATFORM_WINDOWS
if ((*_str)[1] == ':') {
_pos = max(_pos, size_t(3));
}
#else
if ((*_str)[0] == '/') {
_pos = max(_pos, size_t(1));
}
#endif
// Ensure we are at the start of a directory/file name
if (_pos != 0 && (*_str)[_pos - 1] != '/') {
_pos = _str->find('/', _pos) + 1;
}
}
constexpr iterator(const iterator&) = default;
constexpr iterator(iterator&&) noexcept = default;
constexpr string operator*() const {
if ((*_str)[_pos] == '/') {
return string("");
}
size_t e = _str->find('/', _pos);
return _str->substring(_pos, e - _pos);
}
constexpr iterator& operator++() {
_pos = min(_str->find('/', _pos) + 1, _str->size());
return *this;
}
constexpr iterator operator++(int) {
iterator it = *this;
this->operator++();
return it;
}
constexpr bool operator==(const iterator& rhs) const {
return _str == rhs._str and _pos == rhs._pos;
}
constexpr bool operator!=(const iterator& rhs) const {
return _str != rhs._str or _pos != rhs._pos;
}
private:
const string* _str;
size_t _pos;
};
private: private:
string _str; string _str;
}; };

View File

@@ -627,7 +627,7 @@ public:
return _data; return _data;
} }
private: protected:
alloc_t _alloc; // Allocator object alloc_t _alloc; // Allocator object
value_t* _data; // Handle for the memory block value_t* _data; // Handle for the memory block
size_t _capacity; // Capacity of the memory block in elements. size_t _capacity; // Capacity of the memory block in elements.

View File

@@ -21,19 +21,27 @@
#include <fennec/containers/dynarray.h> #include <fennec/containers/dynarray.h>
#include <fennec/containers/map.h> #include <fennec/containers/map.h>
#include <fennec/containers/object_pool.h>
#include <fennec/containers/optional.h> #include <fennec/containers/optional.h>
#include <fennec/containers/rdtree.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/lang/typed.h> #include <fennec/lang/typed.h>
#include <fennec/langproc/filesystem/path.h>
namespace fennec namespace fennec
{ {
class component : typed<component> { struct component_t {
uint64_t type;
size_t id;
};
class component : public typed<component> {
public: public:
// TYPEDEFS & CONSTANTS ================================================================================================ // TYPEDEFS & CONSTANTS ================================================================================================
using component_create = component (*)(size_t); using component_create = size_t (*)(size_t, size_t);
using component_find = component* (*)(size_t); using component_get = component* (*)(size_t);
using component_destroy = void (*)(size_t); using component_destroy = void (*)(size_t);
using component_tick = void (*)(size_t, double); using component_tick = void (*)(size_t, double);
using component_frame = void (*)(size_t, uint64_t); using component_frame = void (*)(size_t, uint64_t);
@@ -41,44 +49,146 @@ public:
// TYPE OPERATIONS ===================================================================================================== // TYPE OPERATIONS =====================================================================================================
struct type_info { struct typeinfo {
string name; string name;
component_create create; component_create create;
component_find find;
component_destroy destroy; component_destroy destroy;
component_get get;
component_tick tick; component_tick tick;
component_frame frame; component_frame frame;
typeinfo()
: name("")
, create(nullptr), destroy(nullptr)
, get(nullptr)
, tick(nullptr), frame(nullptr) {
}
typeinfo(const string& name,
component_create create, component_destroy destroy,
component_get get,
component_tick tick, component_frame frame)
: name(name)
, create(create), destroy(destroy), get(get)
, tick(tick), frame(frame) {
}
}; };
struct typeentry {
string name;
uint64_t id;
};
using typelist_t = dynarray<optional<typeinfo>>;
using typetree_t = rdtree<typeentry>;
// Private Registry ====================================================================================================
private: private:
// Private Registry
static auto& _type_list() { static typelist_t _typelist; // Actual list of types
static dynarray<optional<type_info>> type_list; static typetree_t _typetree; // Tree for displaying types under subfolders
return type_list;
}
static void _register_type( uint64_t id, const cstring& name, static constexpr size_t npos = typetree_t::npos;
component_create create, component_find find, component_destroy destroy, static constexpr size_t root = typetree_t::root;
component_tick tick, component_frame frame) {
auto& type_list = _type_list(); static void _register_type( uint64_t id, const path& path,
if (id > type_list.size()) { component_create create, component_destroy destroy,
type_list.resize(id + 1); component_get get,
component_tick tick, component_frame frame) {
// Register the type
if (id > _typelist.size()) {
_typelist.resize(id + 1);
}
_typelist[id] = typeinfo{ path.filename(), create, destroy, get, tick, frame };
// Create tree entry
size_t node = root;
path::iterator it = path.begin();
while (it != path.end()) {
string name = *it++;
size_t parent = node;
bool end = it == path.end();
node = _typetree.child(parent);
while (node != npos && _typetree[node].id != id) {
node = _typetree.next(node);
}
if (node == npos) {
node = _typetree.emplace(
parent, npos,
name, end ? id : nullid
);
}
} }
type_list[id] = type_info{ name, create, find, destroy, tick, frame };
} }
static void _unregister_type(uint64_t id) { struct noderef {
_type_list()[id] = nullopt; size_t scene, node;
};
using compstorage_t = object_pool<component*>; // Holds refs to default allocated components
using defaultstorage_t = map<uint64_t, compstorage_t>; // Maps types to respective storage
inline static defaultstorage_t _default_storage;
static auto& _type_info(uint64_t type) {
return _typelist[type];
} }
static auto& _default_storage() { template<typename ComponentT>
static map<uint64_t, map<size_t, component*>> data; static auto& _type_info() {
return data; return _typelist[uuid<ComponentT>()];
} }
static auto& _type_storage(uint64_t type) {
return *_default_storage[type];
}
template<typename ComponentT>
static auto& _type_storage() {
return *_default_storage[uuid<ComponentT>()];
}
///
/// \brief Default creation function for a component
/// \tparam ComponentT Type of the component
/// \param node The node to associate the component with
/// \returns The component created by this function
template<typename ComponentT>
static constexpr component* default_create(size_t scene, size_t node) {
auto& storage = _type_storage<ComponentT>();
return storage.insert(new ComponentT(scene, node));
}
///
/// \brief Default destruction function for a component
/// \tparam ComponentT Type of the component
/// \param node The node the component is associated with
template<typename ComponentT>
static constexpr void default_destroy(size_t comp) {
auto& storage = _type_storage<ComponentT>();
delete storage[comp];
storage.erase(comp);
}
///
/// \brief Default retrieval function for a component
/// \tparam ComponentT Type of the component
/// \param node The node the component is associated with
/// \returns The component found by this function
template<typename ComponentT>
static constexpr component* default_get(size_t comp) {
auto& storage = _type_storage<ComponentT>();
return storage[comp];
}
// Public Registry =====================================================================================================
public: public:
// Public Registry
/// ///
/// \brief Get an uuid for the specified component type /// \brief Get an uuid for the specified component type
@@ -89,66 +199,30 @@ public:
return typeuuid<ComponentT, component>(); return typeuuid<ComponentT, component>();
} }
///
/// \brief Default storage function for default creation, retrieval, and destruction
template<typename ComponentT>
static constexpr auto& default_storage() {
auto& data = _default_storage();
return data[uuid<ComponentT>()];
}
///
/// \brief Default creation function for a component
/// \tparam ComponentT Type of the component
/// \param node The node to associate the component with
/// \returns The component created by this function
template<typename ComponentT>
static constexpr component* default_create(size_t node) {
auto& storage = default_storage<ComponentT>();
if (not storage[node]) {
storage.emplace(node);
}
return storage[node];
}
///
/// \brief Default retrieval function for a component
/// \tparam ComponentT Type of the component
/// \param node The node the component is associated with
/// \returns The component found by this function
template<typename ComponentT>
static constexpr component* default_find(size_t node) {
auto& storage = default_storage<ComponentT>();
return storage[node];
}
///
/// \brief Default destruction function for a component
/// \tparam ComponentT Type of the component
/// \param node The node the component is associated with
template<typename ComponentT>
static constexpr void default_destroy(size_t node) {
default_storage<ComponentT>().erase(node);
}
/// ///
/// \brief Register a type with the component system /// \brief Register a type with the component system
/// \tparam ComponentT The component type /// \tparam ComponentT The component type
/// \param name The name of the type /// \param name The name of the type
/// \param create The function used to create a component, given a scene node. **MUST NOT BE NULL** /// \param create The function used to create a component, given a scene node. **MUST NOT BE NULL**
/// \param find The function used to find a component, given a scene node. **MUST NOT BE NULL** /// \param get The function used to find a component, given a scene node. **MUST NOT BE NULL**
/// \param destroy The function used to destroy a component of a scene node. **MUST NOT BE NULL** /// \param destroy The function used to destroy a component of a scene node. **MUST NOT BE NULL**
template<typename ComponentT> template<typename ComponentT>
static void register_type(const cstring& name, component_tick tick, component_frame frame, static void register_type(const cstring& name,
component_tick tick, component_frame frame,
component_create create = default_create<ComponentT>, component_create create = default_create<ComponentT>,
component_find find = default_find<ComponentT>, component_get get = default_get<ComponentT>,
component_destroy destroy = default_destroy<ComponentT>) { component_destroy destroy = default_destroy<ComponentT>) {
component::_register_type(uuid<ComponentT>(), name, create, find, destroy, tick, frame); component::_register_type(uuid<ComponentT>(), name, create, destroy, get, tick, frame);
} }
template<typename ComponentT> ///
static void unregister_type() { /// \brief Create a component of type `type`
component::_unregister_type(uuid<ComponentT>()); /// \param type The type to create
/// \param node The node to associate the component with
/// \returns The created component
static size_t create(uint64_t type, size_t scene, size_t node) {
auto& typei = _typelist[type];
return typei->create(scene, node);
} }
/// ///
@@ -157,42 +231,60 @@ public:
/// \param node The node to associate the component with /// \param node The node to associate the component with
/// \returns The created component /// \returns The created component
template<typename ComponentT> template<typename ComponentT>
static component* create(size_t node) { static size_t create(size_t scene, size_t node) {
auto& type = _type_list()[uuid<ComponentT>()]; auto& typei = _typelist[uuid<ComponentT>()];
return type ? *type->create(node) : nullptr; return typei->create(scene, node);
}
///
/// \brief Get a component of type `type` from id `id`
/// \param type The type of component
/// \param id The id of the component instance
/// \return
static component* get(uint64_t type, size_t id) {
auto& typei = _typelist[type];
return typei->get(id);
} }
template<typename ComponentT> template<typename ComponentT>
static component* find(size_t node) { static component* get(size_t comp) {
auto& type = _type_list()[uuid<ComponentT>()]; auto& typei = _typelist[uuid<ComponentT>()];
return type ? *type->find(node) : nullptr; return typei->get(comp);
}
static void destroy(size_t type, size_t comp) {
auto& typei = _typelist[type];
return typei->destroy(comp);
} }
template<typename ComponentT> template<typename ComponentT>
static void destroy(size_t node) { static void destroy(size_t comp) {
auto& type = _type_list()[uuid<ComponentT>()]; auto& typei = _typelist[uuid<ComponentT>()];
return type ? *type->destroy(node) : nullptr; return typei->destroy(comp);
} }
static void tick(size_t node, double dT) { static void tick(size_t comp, double dT) {
for (auto& it : _type_list()) { for (auto& it : _typelist) {
it->tick(node, dT); if (it->tick) {
it->tick(comp, dT);
}
} }
} }
static void frame(size_t node, uint64_t f) { static void frame(size_t comp, uint64_t f) {
for (auto& it : _type_list()) { for (auto& it : _typelist) {
it->tick(node, f); if (it->frame) {
it->frame(comp, f);
}
} }
} }
static const auto& type_list() { static const auto& type_list() {
return _type_list(); return _typelist;
} }
// MEMBERS ============================================================================================================= // MEMBERS =============================================================================================================
public: public:
const type_info* type;
const size_t node; const size_t node;
template<typename ComponentT> template<typename ComponentT>

View File

@@ -33,12 +33,12 @@
#include <fennec/math/matrix.h> #include <fennec/math/matrix.h>
#include <fennec/math/ext/transform.h> #include <fennec/math/ext/transform.h>
#include <fennec/scene/component.h> #include <fennec/scene/scene_node.h>
namespace fennec namespace fennec
{ {
struct transform2d : component { struct node2d : scene_node {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
enum mobility_ : bool { enum mobility_ : bool {
@@ -52,34 +52,19 @@ public:
/// ///
/// \brief Default Constructor, initializes an identity matrix. /// \brief Default Constructor, initializes an identity matrix.
transform2d(size_t node) node2d(size_t id, size_t scene, const string& name)
: component(this, node) : scene_node(name, id, scene)
, _mobility(mobility_free)
, _position(0, 0) , _position(0, 0)
, _scale(1, 1) , _scale(1, 1)
, _shear(0, 0) , _shear(0, 0)
, _rotation(0) { , _rotation(0) {
} }
/// node2d(const node2d&) = default;
/// \brief Component Constructor, composes the internal matrix using the components. node2d(node2d&&) noexcept = default;
/// \param pos Position as vec2
/// \param scl Scale as vec2
/// \param rot Rotation as degrees
/// \param skw Skew as vec2
transform2d(size_t node, const vec2& pos, const vec2& scl, float rot, const vec2& skw = vec2(0, 0))
: component(this, node)
, _position(pos)
, _scale(scl)
, _shear(skw)
, _rotation(rot)
, _dirty(true)
, _local(matrix()) {
}
transform2d(const transform2d&) = default; ~node2d() = default;
transform2d(transform2d&&) noexcept = default;
~transform2d() = default;
// Access ============================================================================================================== // Access ==============================================================================================================
@@ -99,53 +84,79 @@ public:
return _shear; return _shear;
} }
constexpr bool mobility() const {
return _mobility;
}
// Modifiers =========================================================================================================== // Modifiers ===========================================================================================================
constexpr void translate(const vec2& x) { constexpr void translate(const vec2& x) {
_position += x; if (_mobility) {
_position += x;
}
} }
constexpr void scale(const vec2& s) { constexpr void scale(const vec2& s) {
_scale *= s; if (_mobility) {
_scale *= s;
}
} }
constexpr void rotate(float r) { constexpr void rotate(float r) {
_rotation += r; if (_mobility) {
_rotation += r;
}
} }
constexpr void shear(const vec2& s) { constexpr void shear(const vec2& s) {
_shear += s; if (_mobility) {
_shear += s;
}
} }
constexpr void commit() { constexpr void commit() {
if (not _dirty) { if (not _mobility) {
return; return;
} }
_local = fennec::rotation(_rotation); // Get parent
_local *= fennec::shear(_shear);
_local *= fennec::scaling(_scale);
_local *= fennec::translation(_position); _recalculate();
// Propagate down
} }
constexpr const mat3& local() { constexpr const mat3& local() {
commit();
return _local; return _local;
} }
constexpr const mat3& global() { constexpr const mat3& global() {
return _global;
} }
// Fields ============================================================================================================== // Fields ==============================================================================================================
private: private:
bool _mobility;
vec2 _position; vec2 _position;
vec2 _scale; vec2 _scale;
vec2 _shear; vec2 _shear;
float _rotation; float _rotation;
bool _dirty; mat3 _local, _global;
mat3 _local;
// Helpers =============================================================================================================
constexpr void _recalculate(const mat3& parent) {
_local = fennec::rotation(_rotation);
_local *= fennec::shear(_shear);
_local *= fennec::scaling(_scale);
_local *= fennec::translation(_position);
_global = parent * _local;
}
}; };
} }

View File

@@ -20,7 +20,10 @@
#define FENNEC_CORE_SCENE_H #define FENNEC_CORE_SCENE_H
#include <fennec/containers/rdtree.h> #include <fennec/containers/rdtree.h>
#include <fennec/lang/typed.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/scene/scene_node.h>
namespace fennec namespace fennec
{ {
@@ -30,9 +33,10 @@ namespace fennec
/// \details This structure only contains the names of nodes and defers storage for components to /// \details This structure only contains the names of nodes and defers storage for components to
/// their respective systems. Simple components may be isolated, \see components.h for more info. /// their respective systems. Simple components may be isolated, \see components.h for more info.
/// The hierarchy should be displayed using pre-order traversal. /// The hierarchy should be displayed using pre-order traversal.
class scene : public rdtree<string> { class scene : public rdtree<scene_node*> {
public:
// Access ==============================================================================================================
public:
/// ///
/// \brief Find a node by name. /// \brief Find a node by name.
/// \details If multiple nodes have the same name, finds the first one in pre-order traversal. /// \details If multiple nodes have the same name, finds the first one in pre-order traversal.
@@ -42,13 +46,14 @@ public:
list<size_t> parse; list<size_t> parse;
parse.push_back(root); parse.push_back(root);
while (not parse.empty()) { while (not parse.empty()) {
if (*_data[parse.front()].value == name) { size_t n = parse.front();
return parse.front(); if (_table[n].value->name == name) {
return n;
} }
// Pre-Order traversal // Pre-Order traversal
parse.push_front(next(parse.front())); parse.push_front(next(n));
parse.push_front(child(parse.front())); parse.push_front(child(n));
parse.pop_front(); parse.pop_front();
} }
return npos; return npos;
@@ -63,13 +68,14 @@ public:
list<size_t> parse; list<size_t> parse;
parse.push_back(root); parse.push_back(root);
while (not parse.empty()) { while (not parse.empty()) {
if (*_data[parse.front()].value == name) { size_t n = parse.front();
return parse.front(); if (_table[n].value->name == name) {
return n;
} }
// Pre-Order traversal // Pre-Order traversal
parse.push_front(next(parse.front())); parse.push_front(next(n));
parse.push_front(child(parse.front())); parse.push_front(child(n));
parse.pop_front(); parse.pop_front();
} }
return npos; return npos;

View File

@@ -0,0 +1,56 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file node.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_SCENE_NODE_H
#define FENNEC_SCENE_NODE_H
#include <fennec/lang/typed.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/scene/component.h>
namespace fennec
{
struct scene_node : typed<scene_node> {
const size_t scene;
const size_t id;
string name;
scene_node(size_t id, size_t scene, const string& name)
: id(id), scene(scene), name(name) {
}
private:
dynarray<component_t> _components;
};
}
#endif // FENNEC_SCENE_NODE_H