- Refactor on component system to support multiple scenes.
- node2d for 2d scenes
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ 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;
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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) {
|
for (char c : delimiter) {
|
||||||
idx.emplace()
|
size_t i = 0;
|
||||||
|
while (i != line.size()) {
|
||||||
|
size_t n = line.find(c, i);
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
static void _register_type( uint64_t id, const path& path,
|
||||||
|
component_create create, component_destroy destroy,
|
||||||
|
component_get get,
|
||||||
component_tick tick, component_frame frame) {
|
component_tick tick, component_frame frame) {
|
||||||
auto& type_list = _type_list();
|
// Register the type
|
||||||
if (id > type_list.size()) {
|
if (id > _typelist.size()) {
|
||||||
type_list.resize(id + 1);
|
_typelist.resize(id + 1);
|
||||||
}
|
}
|
||||||
type_list[id] = type_info{ name, create, find, destroy, tick, frame };
|
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _unregister_type(uint64_t id) {
|
if (node == npos) {
|
||||||
_type_list()[id] = nullopt;
|
node = _typetree.emplace(
|
||||||
|
parent, npos,
|
||||||
|
name, end ? id : nullid
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto& _default_storage() {
|
struct noderef {
|
||||||
static map<uint64_t, map<size_t, component*>> data;
|
size_t scene, node;
|
||||||
return data;
|
};
|
||||||
|
|
||||||
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ComponentT>
|
||||||
|
static auto& _type_info() {
|
||||||
|
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>
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
if (_mobility) {
|
||||||
_position += x;
|
_position += x;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void scale(const vec2& s) {
|
constexpr void scale(const vec2& s) {
|
||||||
|
if (_mobility) {
|
||||||
_scale *= s;
|
_scale *= s;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void rotate(float r) {
|
constexpr void rotate(float r) {
|
||||||
|
if (_mobility) {
|
||||||
_rotation += r;
|
_rotation += r;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void shear(const vec2& s) {
|
constexpr void shear(const vec2& s) {
|
||||||
|
if (_mobility) {
|
||||||
_shear += s;
|
_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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
56
include/fennec/scene/scene_node.h
Normal file
56
include/fennec/scene/scene_node.h
Normal 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
|
||||||
Reference in New Issue
Block a user