diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5577ed2..41f6fa1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -247,6 +247,7 @@ add_library(fennec STATIC
# EXTRA SOURCES ========================================================================================================
${FENNEC_EXTRA_SOURCES}
+ include/fennec/gfx3d/mesh_instance.h
)
add_dependencies(fennec metaprogramming fennec-dependencies)
diff --git a/cmake/gcc.cmake b/cmake/gcc.cmake
index 74fc81d..53569fa 100644
--- a/cmake/gcc.cmake
+++ b/cmake/gcc.cmake
@@ -18,7 +18,7 @@
# this script sets flags and variables for gnu and gnu-like compilers
-add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror")
+add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror" "-fms-extensions")
fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
diff --git a/include/fennec/gfx3d/mesh_instance.h b/include/fennec/gfx3d/mesh_instance.h
new file mode 100644
index 0000000..03041a4
--- /dev/null
+++ b/include/fennec/gfx3d/mesh_instance.h
@@ -0,0 +1,47 @@
+// =====================================================================================================================
+// 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 .
+// =====================================================================================================================
+
+///
+/// \file mesh_instance.h
+/// \brief
+///
+///
+/// \details
+/// \author Medusa Slockbower
+///
+/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
+///
+///
+
+#ifndef FENNEC_GFX3D_MESH_INSTANCE_H
+#define FENNEC_GFX3D_MESH_INSTANCE_H
+#include
+
+namespace fennec
+{
+
+class mesh_instance : component {
+public:
+
+
+private:
+};
+
+}
+
+#endif // FENNEC_GFX3D_MESH_INSTANCE_H
\ No newline at end of file
diff --git a/include/fennec/lang/startup.h b/include/fennec/lang/startup.h
index d4de864..9f299b4 100644
--- a/include/fennec/lang/startup.h
+++ b/include/fennec/lang/startup.h
@@ -20,7 +20,7 @@
#define FENNEC_LANG_STARTUP_H
// Helper for running a function before main()
-#define STATIC_CONSTRUCTOR(f) \
+#define FENNEC_STATIC_CONSTRUCTOR(f) \
inline static void f(void); \
struct f##_t_ { inline f##_t_(void) { f(); } }; inline static f##_t_ f##_; \
inline static void f(void)
diff --git a/include/fennec/lang/typed.h b/include/fennec/lang/typed.h
index c79d60c..3d3f9c5 100644
--- a/include/fennec/lang/typed.h
+++ b/include/fennec/lang/typed.h
@@ -54,6 +54,11 @@ public:
typed(TypeT*)
: type(typeuuid()) {
}
+
+ template
+ static uint64_t id() {
+ return typeuuid();
+ }
};
}
diff --git a/include/fennec/langproc/strings/format.h b/include/fennec/langproc/strings/format.h
index 4dee0c9..200b0f9 100644
--- a/include/fennec/langproc/strings/format.h
+++ b/include/fennec/langproc/strings/format.h
@@ -66,12 +66,16 @@ struct format_string {
private:
static constexpr size_t npos = -1;
- enum token_ : uint8_t {
- token_text = 0,
- token_param,
+ enum token_ : bool {
+ token_text = false,
+ token_param = true,
};
- using token = pair;
+ struct token {
+ uint8_t type;
+ string_view view;
+ size_t param;
+ };
constexpr const char* find(const char* start, char c) {
while (*start != c && *start != '\0') {
@@ -80,47 +84,64 @@ private:
return start;
}
+ constexpr size_t parse_index(const char* start, size_t n) {
+ size_t x = 0;
+ while (n-- > 0) {
+ x *= 10;
+ x += *start - '0';
+ }
+ return x;
+ }
+
// Constructors & Destructor ===========================================================================================
public:
format_string() = delete;
- format_string(const char (&str)[N])
+ constexpr format_string(const char (&str)[N])
: _tokens(), _num_tokens(0) {
- static_assert(is_constant_evaluated(), "Runtime format strings are not supported.");
-
// TODO: Numbered Parameters
- size_t params = 0;
- for (size_t i = 0; i < N; ++i) {
- size_t n = this->find(str + i, '{') - str;
+ size_t params = 0;
+ for (size_t i = 0; i < N - 1; ++i) {
+ size_t l = this->find(str + i, '{') - str;
// Push the current token
- if (n - i > 0) {
- _tokens[_num_tokens++] = { token_text, { &str[i], n - i } };
+ if (l - i > 0) {
+ _tokens[_num_tokens++] = { token_text, { &str[i], l - i }, npos };
}
// no more braces, break
- if (n >= N) {
+ if (l >= N) {
break;
}
// escaped brace
- if (str[n + 1] == '{') {
- _tokens[_num_tokens++] = { token_text, { &str[n], 1 } };
- i = n + 1;
+ if (str[l + 1] == '{') {
+ _tokens[_num_tokens++] = { token_text, { &str[l], 1 }, npos };
+ i = l + 1;
continue;
}
- size_t e = this->find(str + n, '}') - str;
- //static_assert(e >= N, "Malformed format string, mismatched brace");
+ size_t e = this->find(str + l, '}') - str;
+ assertd(e < N, "Malformed format string, mismatched brace");
- _tokens[_num_tokens++] = { token_param, { &str[n], e - n + 1 } };
- ++params;
+ // Colon found
+ size_t c = this->find(str + l, ':') - str;
+ if (c < e) {
+ size_t n = c - l;
+ if (n > 1) { // Check if index is provided
+ params = this->parse_index(str + l + 1, n - 1);
+ }
+ l = c;
+ } else if (e - l > 1) { // check if index is provided
+ params = this->parse_index(str + l + 1, e - l - 1);
+ }
+
+ assertd(params < sizeof...(ArgsT), "Malformed format string, parameter count does not match argument count.");
+ _tokens[_num_tokens++] = { token_param, { &str[l + 1], e - l - 1 }, params++ };
i = e;
}
-
- //static_assert(params == sizeof...(ArgsT), "Malformed format string, parameter count does not match argument count.");
}
constexpr format_string(const format_string&) = default;
@@ -129,33 +150,48 @@ public:
~format_string() = default;
string format(ArgsT&&...args) const {
- return this->_format(0, fennec::forward(args)...);
+ string parts[N];
+
+ // Copy raw text tokens
+ size_t i = 0;
+ for (i = 0; i < _num_tokens; ++i) {
+ const token& tok = _tokens[i];
+ if (not tok.type) {
+ parts[i] = tok.view;
+ }
+ }
+
+ // Copy arguments
+ this->_format(0, parts, fennec::forward(args)...);
+
+ string res;
+ for (i = 0; i < _num_tokens; ++i) {
+ res += parts[i];
+ }
+ return res;
}
private:
array _tokens;
size_t _num_tokens;
- string _format(size_t) const {
- return string{""};
+ void _format(size_t) const {
}
template
- string _format(size_t i, HeadT&& head, RestT&&...rest) const {
- string res;
- for (; i < _num_tokens; ++i) {
- const auto& token = _tokens[i];
-
- if (token.first == token_param) {
- formatter fmt;
- res += fmt(token.second, head);
- res += this->_format(i + 1, fennec::forward(rest)...);
+ void _format(size_t p, string (&parts)[N], HeadT&& head, RestT&&...rest) const {
+ size_t i = 0;
+ for (const token& tok : _tokens) {
+ if (i >= _num_tokens) {
break;
}
-
- res += token.second;
+ if (tok.param == p) {
+ formatter fmt;
+ parts[i] = fmt(tok.view, head);
+ }
+ ++i;
}
- return res;
+ this->_format(p + 1, fennec::forward(rest)...);
}
};
diff --git a/include/fennec/renderers/opengl/lib/buffer.h b/include/fennec/renderers/opengl/lib/buffer.h
index 22f136b..eed39bc 100644
--- a/include/fennec/renderers/opengl/lib/buffer.h
+++ b/include/fennec/renderers/opengl/lib/buffer.h
@@ -55,9 +55,9 @@ private:
GLenum res;
// Set READ/DRAW/COPY
- if constexpr (read) {
+ if constexpr (map_read) {
res = GL_STREAM_READ;
- } else if constexpr (write) {
+ } else if constexpr (map_write) {
res = GL_STREAM_DRAW;
} else {
res = GL_STREAM_COPY;
diff --git a/include/fennec/scene/component.h b/include/fennec/scene/component.h
index c1cb442..06e17f7 100644
--- a/include/fennec/scene/component.h
+++ b/include/fennec/scene/component.h
@@ -21,30 +21,27 @@
#include
#include
-#include
#include
#include
+#include
#include
#include
#include
+#define FENNEC_REGISTER_COMPONENT(T, p) \
+ FENNEC_STATIC_CONSTRUCTOR(T) { \
+ component::register_type(p) \
+ }
+
namespace fennec
{
-struct component_t {
- uint64_t type;
- size_t id;
-};
-
class component : public typed {
public:
// TYPEDEFS & CONSTANTS ================================================================================================
- using component_create = size_t (*)(size_t, size_t);
- using component_get = component* (*)(size_t);
- using component_destroy = void (*)(size_t);
- using component_tick = void (*)(size_t, double);
- using component_frame = void (*)(size_t, uint64_t);
+ using component_create = component* (*)(size_t, size_t);
+ using component_destroy = void (*)(component*);
// TYPE OPERATIONS =====================================================================================================
@@ -52,31 +49,22 @@ public:
struct typeinfo {
string name;
component_create create;
- component_destroy destroy;
- component_get get;
- component_tick tick;
- component_frame frame;
typeinfo()
: name("")
- , create(nullptr), destroy(nullptr)
- , get(nullptr)
- , tick(nullptr), frame(nullptr) {
+ , create(nullptr) {
}
typeinfo(const string& name,
- component_create create, component_destroy destroy,
- component_get get,
- component_tick tick, component_frame frame)
+ component_create create)
: name(name)
- , create(create), destroy(destroy), get(get)
- , tick(tick), frame(frame) {
+ , create(create) {
}
};
struct typeentry {
- string name;
- uint64_t id;
+ string name;
+ uint64_t type;
};
using typelist_t = dynarray>;
@@ -92,15 +80,13 @@ private:
static constexpr size_t npos = typetree_t::npos;
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) {
+ static void _register_type( uint64_t id, const path& path,
+ component_create create) {
// Register the type
if (id > _typelist.size()) {
_typelist.resize(id + 1);
}
- _typelist[id] = typeinfo{ path.filename(), create, destroy, get, tick, frame };
+ _typelist[id] = typeinfo{ path.filename(), create };
// Create tree entry
size_t node = root;
@@ -112,7 +98,7 @@ private:
node = _typetree.child(parent);
- while (node != npos && _typetree[node].id != id) {
+ while (node != npos && _typetree[node].type != id) {
node = _typetree.next(node);
}
@@ -125,33 +111,6 @@ private:
}
}
- struct noderef {
- size_t scene, node;
- };
-
- using compstorage_t = object_pool; // Holds refs to default allocated components
- using defaultstorage_t = map; // Maps types to respective storage
-
- inline static defaultstorage_t _default_storage;
-
- static auto& _type_info(uint64_t type) {
- return _typelist[type];
- }
-
- template
- static auto& _type_info() {
- return _typelist[uuid()];
- }
-
- static auto& _type_storage(uint64_t type) {
- return *_default_storage[type];
- }
-
- template
- static auto& _type_storage() {
- return *_default_storage[uuid()];
- }
-
///
/// \brief Default creation function for a component
/// \tparam ComponentT Type of the component
@@ -159,60 +118,39 @@ private:
/// \returns The component created by this function
template
static constexpr component* default_create(size_t scene, size_t node) {
- auto& storage = _type_storage();
- 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
- static constexpr void default_destroy(size_t comp) {
- auto& storage = _type_storage();
-
- 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
- static constexpr component* default_get(size_t comp) {
- auto& storage = _type_storage();
- return storage[comp];
+ return new ComponentT(scene, node);
}
// Public Registry =====================================================================================================
public:
- ///
- /// \brief Get an uuid for the specified component type
- /// \tparam ComponentT The component type
- /// \returns An uuid that is associated with the type
+ static constexpr const typetree_t& typelist() {
+ return _typetree;
+ }
+
template
- static uint64_t uuid() {
- return typeuuid();
+ static constexpr const typeinfo& type_info() {
+ const auto& it = _typelist[id()];
+ assert(it, "Unregistered type provided to component::type_info, see stacktrace for more info.");
+ return *it;
+ }
+
+ static constexpr const typeinfo& type_info(uint64_t type) {
+ const auto& it = _typelist[type];
+ assert(it, "Unregistered type provided to component::type_info, see stacktrace for more info.");
+ return *it;
}
///
/// \brief Register a type with the component system
/// \tparam ComponentT The component type
- /// \param name The name of the type
+ /// \param path The name of the type
/// \param create The function used to create 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**
template
- static void register_type(const cstring& name,
- component_tick tick, component_frame frame,
- component_create create = default_create,
- component_get get = default_get,
- component_destroy destroy = default_destroy) {
- component::_register_type(uuid(), name, create, destroy, get, tick, frame);
+ static void register_type(const path& path,
+ component_create create = default_create) {
+ component::_register_type(id(), path, create);
}
///
@@ -220,72 +158,25 @@ public:
/// \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) {
+ static component* create(uint64_t type, size_t scene, size_t node) {
auto& typei = _typelist[type];
return typei->create(scene, node);
}
///
- /// \brief Create a component of type `ComponentT`
+ /// \brief Create a component of type `type`
/// \tparam ComponentT The type to create
/// \param node The node to associate the component with
/// \returns The created component
template
- static size_t create(size_t scene, size_t node) {
- auto& typei = _typelist[uuid()];
+ static component* create(size_t scene, size_t node) {
+ auto& typei = _typelist[id()];
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(const component_t& c) {
- auto& typei = _typelist[c.type];
- return typei->get(c.id);
- }
-
- template
- static component* get(size_t id) {
- auto& typei = _typelist[uuid()];
- return typei->get(id);
- }
-
- static void destroy(size_t type, size_t comp) {
- auto& typei = _typelist[type];
- return typei->destroy(comp);
- }
-
- template
- static void destroy(size_t comp) {
- auto& typei = _typelist[uuid()];
- return typei->destroy(comp);
- }
-
- static void tick(size_t comp, double dT) {
- for (auto& it : _typelist) {
- if (it->tick) {
- it->tick(comp, dT);
- }
- }
- }
-
- static void frame(size_t comp, uint64_t f) {
- for (auto& it : _typelist) {
- if (it->frame) {
- it->frame(comp, f);
- }
- }
- }
-
- static const auto& type_list() {
- return _typelist;
- }
-
// MEMBERS =============================================================================================================
public:
- const size_t node;
+ const size_t node;
template
component(ComponentT* type, size_t node)
diff --git a/include/fennec/scene/scene_node.h b/include/fennec/scene/scene_node.h
index a33c12f..f297235 100644
--- a/include/fennec/scene/scene_node.h
+++ b/include/fennec/scene/scene_node.h
@@ -35,20 +35,47 @@
#include
#include
+#include
+
namespace fennec
{
+struct scene_node_ref {
+ size_t scene;
+ size_t id;
+};
+
struct scene_node : typed {
- const size_t scene;
- const size_t id;
+
+// Public Members ======================================================================================================
+public:
+ union {
+ struct {
+ const size_t scene;
+ const size_t id;
+ };
+ const scene_node_ref ref;
+ };
string name;
- scene_node(size_t id, size_t scene, const string& name)
- : id(id), scene(scene), name(name) {
+ scene_node(size_t scene, size_t id, string name)
+ : scene(scene), id(id), name(std::move(name)) {
}
+ template
+ component* add_component() {
+ _components.push_back(component::create(scene, id));
+ return _components.back();
+ }
+
+ component* add_component(uint64_t type) {
+ _components.push_back(component::create(type, scene, id));
+ return _components.back();
+ }
+
+
private:
- dynarray _components;
+ dynarray _components;
};
}
diff --git a/source/platform/linux/platform.cpp b/source/platform/linux/platform.cpp
index 4d4f5c8..3175c5d 100644
--- a/source/platform/linux/platform.cpp
+++ b/source/platform/linux/platform.cpp
@@ -24,7 +24,7 @@
namespace fennec
{
-STATIC_CONSTRUCTOR(_init_linux) {
+FENNEC_STATIC_CONSTRUCTOR(_init_linux) {
static linux_platform platform;
}
diff --git a/test/main.cpp b/test/main.cpp
index 7f1fb48..433ef20 100644
--- a/test/main.cpp
+++ b/test/main.cpp
@@ -48,7 +48,7 @@ int main(int, char **)
fennec::test::fennec_test_math();
fennec_test_spacer(3);
- fennec_test_header("format processing library");
+ fennec_test_header("language processing library");
fennec_test_spacer(2);
fennec::test::fennec_test_langproc();
fennec_test_spacer(3);
diff --git a/test/tests/langproc/test_format.h b/test/tests/langproc/test_format.h
index 6b3c241..7dc3ab4 100644
--- a/test/tests/langproc/test_format.h
+++ b/test/tests/langproc/test_format.h
@@ -40,7 +40,8 @@ namespace test
inline void fennec_test_langproc_format() {
- fennec_test_run(fennec::format("{}", "Hello World!"), string("Hello World!"));
+ fennec_test_run(fennec::format("{}", "Hello World!"), string("Hello World!"));
+ fennec_test_run(fennec::format("{0}", "Hello World!"), string("Hello World!"));
}
}