- Started interface for renderers

- Renamed fproc -> langproc (I'll probably never settle on a naming convention for this)
 - Refactored set to use median psl
This commit is contained in:
2025-08-02 13:17:20 -04:00
parent 3d4ea4398a
commit 3d42dea9eb
39 changed files with 962 additions and 164 deletions

View File

@@ -94,6 +94,32 @@ public:
return *_table[n].data;
}
void insert(const iterator& it, const value_t& x) {
if (size() == capacity()) {
_expand();
}
size_t n = it._n;
size_t p = _next_free();
fennec::construct(&_table[p].data, x);
if (n == npos) {
if (empty()) {
_root = p;
_table[p].next = npos;
_table[p].prev = npos;
} else {
_table[p].prev = n;
_table[p].next = npos;
_last = n;
}
return;
}
_table[p].next = n;
_table[p].prev = _prev(n);
_table[n].prev = p;
++_size;
}
void insert(const iterator& it, value_t&& x) {
if (size() == capacity()) {
_expand();
@@ -120,35 +146,86 @@ public:
++_size;
}
void insert(size_t i, const value_t& x) {
assert(i <= size(), "Index out of Bounds");
if (size() == capacity()) {
_expand();
}
size_t n = _walk(min(i, size_t(size() - 1)));
size_t p = _next_free();
fennec::construct(&_table[p].data, x);
if (n == npos) {
if (empty()) {
_root = p;
_table[p].next = npos;
_table[p].prev = npos;
} else {
_table[p].prev = n;
_table[p].next = npos;
_last = n;
}
return;
}
_table[p].next = n;
_table[p].prev = _prev(n);
_table[n].prev = p;
++_size;
}
void insert(size_t i, value_t&& x) {
assert(i <= size(), "Index out of Bounds");
if (size() == capacity()) {
_expand();
}
size_t n = _walk(min(i, size_t(size() - 1)));
size_t p = _next_free();
fennec::construct(&_table[p].data, fennec::forward<value_t>(x));
if (n == npos) {
_root = p;
_table[p].data = fennec::forward<value_t>(x);
_table[p].next = npos;
_table[p].prev = npos;
if (empty()) {
_root = p;
_table[p].next = npos;
_table[p].prev = npos;
} else {
_table[p].prev = n;
_table[p].next = npos;
_last = n;
}
return;
}
_table[p].data = fennec::forward<value_t>(x);
if (i == size()) {
_table[p].prev = n;
_last = n;
}
else {
_table[p].next = n;
_table[p].prev = _prev(n);
_table[n].prev = p;
}
_table[p].next = n;
_table[p].prev = _prev(n);
_table[n].prev = p;
++_size;
}
void insert(size_t i, const value_t& x) {
this->insert(i, elem_t(x));
template<typename...ArgsT>
void emplace(size_t i, ArgsT&&...args) {
assert(i <= size(), "Index out of Bounds");
if (size() == capacity()) {
_expand();
}
size_t n = _walk(min(i, size_t(size() - 1)));
size_t p = _next_free();
fennec::construct(&_table[p].data, fennec::forward<ArgsT>(args)...);
if (n == npos) {
if (empty()) {
_root = p;
_table[p].next = npos;
_table[p].prev = npos;
} else {
_table[p].prev = n;
_table[p].next = npos;
_last = n;
}
return;
}
_table[p].next = n;
_table[p].prev = _prev(n);
_table[n].prev = p;
++_size;
}
void push_front(const value_t& x) {
@@ -159,6 +236,11 @@ public:
this->insert(0, fennec::forward<value_t>(x));
}
template<typename...ArgsT>
void emplace_front(ArgsT...args) {
this->emplace(0, fennec::forward<ArgsT>(args)...);
}
void push_back(const value_t& x) {
this->insert(_size, x);
}
@@ -167,6 +249,11 @@ public:
this->insert(_size, fennec::forward<value_t>(x));
}
template<typename...ArgsT>
void emplace_back(ArgsT...args) {
this->emplace(_size, fennec::forward<ArgsT>(args)...);
}
void erase(size_t i) {
size_t j = _walk(i);
if (j == npos) return;
@@ -199,12 +286,20 @@ public:
erase(_size - 1);
}
constexpr value_t& front() {
return *_table[_root].data;
}
constexpr const value_t& front() const {
return *_table[_root].data;
}
constexpr value_t& back() {
return this->operator[](size() - 1);
return *_table[_last].data;
}
constexpr const value_t& back() const {
return this->operator[](size() - 1);
return *_table[_last].data;
}
// ITERATOR ============================================================================================================
@@ -329,7 +424,7 @@ private:
friend class iterator;
constexpr void _expand() {
_table.reallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
_table.creallocate(fennec::max(_table.capacity(), size_t(1)) * 2);
}
struct node {

View File

@@ -0,0 +1,220 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
#ifndef FENNEC_CONTAINERS_RDTREE_H
#define FENNEC_CONTAINERS_RDTREE_H
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/memory/allocator.h>
namespace fennec
{
template<typename TypeT, typename AllocT = allocator<TypeT>>
struct rdtree {
private:
struct node;
public:
using value_t = TypeT;
using alloc_t = typename allocator_traits<AllocT>::template rebind<node>;
static constexpr size_t root = 0;
static constexpr size_t npos = -1;
protected:
struct node {
optional<TypeT> value;
size_t parent, child, prev, next;
template<typename...ArgsT>
constexpr node(size_t p, size_t c, size_t v, size_t n, ArgsT&&...args)
: value(fennec::forward<ArgsT>(args)...)
, parent(p), child(c), prev(v), next(n) {
}
constexpr ~node() {
parent = npos;
child = npos;
prev = npos;
next = npos;
}
};
public:
// Constructors ========================================================================================================
template<typename...ArgsT>
explicit constexpr rdtree(ArgsT&&...args)
: _data(), _freed(), _size(1) {
_data.callocate(10);
fennec::construct(&_data[0], npos, npos, npos, npos, fennec::forward<ArgsT>(args)...);
}
constexpr rdtree(const rdtree& tree)
: _data(tree._data), _freed(tree._freed), _size(tree._size) {
}
constexpr rdtree(rdtree&& tree) noexcept
: _data(fennec::move(tree._data)), _freed(fennec::move(tree._freed)), _size(tree._size) {
}
// Assignment ==========================================================================================================
friend constexpr rdtree& operator=(rdtree& lhs, const rdtree& rhs) {
for (value_t* it : lhs._data) {
fennec::destruct(it);
}
lhs._data = rhs._data;
lhs._freed = rhs._freed;
lhs._size = rhs._size;
return lhs;
}
friend constexpr rdtree& operator=(rdtree& lhs, rdtree&& rhs) noexcept {
for (value_t* it : lhs._data) {
fennec::destruct(it);
}
lhs._data = fennec::move(rhs._data);
lhs._freed = fennec::move(rhs._freed);
lhs._size = rhs._size;
return lhs;
}
// Access ==============================================================================================================
constexpr size_t parent(size_t i) const {
return _data[i].parent;
}
constexpr size_t child(size_t i) const {
return _data[i].child;
}
constexpr size_t next(size_t i) const {
return _data[i].next;
}
constexpr size_t prev(size_t i) const {
return _data[i].prev;
}
constexpr optional<value_t>& operator[](size_t i) {
return *_data[i].value;
}
constexpr const optional<value_t>& operator[](size_t i) const {
return *_data[i].value;
}
// Insertion & Deletion ================================================================================================
///
/// \brief Insertion, creates a node in the tree with parent `parent`
/// \param parent the parent node, if `npos` sets the value of the root node
/// \param val the value to insert
/// \returns the index of the created node
constexpr size_t insert(size_t parent, const value_t& val) {
if (parent == npos || _size == 0) {
if (_size == 0) {
fennec::construct(&_data[root], npos, npos, npos, npos, val);
_size = 1;
} else {
_data[root].value = val;
}
return root;
}
size_t i = _next_free();
size_t n = child(parent);
_data[parent].child = i;
fennec::construct(&_data[i], parent, npos, n, npos);
return i;
}
///
/// \brief Insertion, creates a node in the tree with parent `parent`
/// \param parent the parent node, if `npos` sets the value of the root node
/// \param val the value to insert
/// \returns the index of the created node
constexpr size_t insert(size_t parent, value_t&& val) {
if (parent == npos || _size == 0) {
if (_size == 0) {
fennec::construct(&_data[root], npos, npos, npos, npos, fennec::forward<value_t>(val));
_size = 1;
} else {
_data[root].value = fennec::forward<value_t>(val);
}
return root;
}
size_t i = _next_free();
size_t n = child(parent);
_data[parent].child = i;
fennec::construct(&_data[i], parent, npos, n, npos);
return i;
}
///
/// \brief Erase a node in the tree and all of it's children
/// \param i the index of the node
constexpr void erase(size_t i) {
list<size_t> queue;
if (child(i) != npos) {
queue.push_back(i);
}
while (not queue.empty()) {
size_t n = queue.front(); queue.pop_front();
if (next(n) != npos) queue.push_back(next(n));
if (child(n) != npos) queue.push_back(child(n));
fennec::destruct(&_data[n]);
_freed.push_back(n);
}
fennec::destruct(&_data[i]);
_freed.push_back(i);
}
protected:
allocation<node, alloc_t> _data;
list<size_t> _freed;
size_t _size;
void _expand() {
_data.creallocate(_data.capacity() * 2);
}
size_t _next_free() {
size_t next = _size + 1;
if (not _freed.empty()) {
next = _freed.back();
_freed.pop_back();
}
return next;
}
};
}
#endif // FENNEC_CONTAINERS_RDTREE_H

View File

@@ -22,6 +22,7 @@
// https://programming.guide/robin-hood-hashing.html
#include <fennec/containers/optional.h>
#include <fennec/containers/set.h>
#include <fennec/lang/compare.h>
#include <fennec/math/ext/primes.h>
#include <fennec/memory/allocator.h>
@@ -58,6 +59,7 @@ public:
: _alloc()
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
};
@@ -65,6 +67,7 @@ public:
: _alloc()
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -72,6 +75,7 @@ public:
: _alloc()
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -79,6 +83,7 @@ public:
: _alloc(alloc)
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -86,6 +91,7 @@ public:
: _alloc(alloc)
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -93,6 +99,7 @@ public:
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -100,6 +107,7 @@ public:
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -107,6 +115,7 @@ public:
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -114,6 +123,7 @@ public:
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
@@ -121,13 +131,16 @@ public:
: _alloc(set._alloc)
, _hash(set._hash)
, _size(set._size)
, _load(default_load) {
, _sumpsl(set._sumpsl)
, _load(set._load) {
}
constexpr set(set&& set) noexcept
: _alloc(fennec::move(set._alloc))
, _hash(fennec::move(set._hash))
, _size(fennec::move(set._size)) {
, _size(fennec::move(set._size))
, _sumpsl(set._sumpsl)
, _load(set._load) {
}
constexpr ~set() = default;
@@ -153,13 +166,14 @@ public:
return;
}
if (psl > _alloc[i].psl) { // When psl is higher, swap
fennec::swap(*_alloc[i].value, value);
_sumpsl += psl - _alloc[i].psl;
fennec::swap(_alloc[i].psl, psl);
fennec::swap(*_alloc[i].value, value);
}
i = (i + 1) % capacity(); ++psl;
}
_alloc[i].value = fennec::move(value);
_alloc[i].psl = psl;
_sumpsl += (_alloc[i].psl = psl);
++_size;
}
@@ -175,15 +189,41 @@ public:
}
constexpr iterator find(const elem_t& val) const {
size_t i = _hash(val) % capacity(); // Initial search index
int psl = 0;
size_t s = _hash(val) % capacity(); // Initial search index
int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl
size_t i = (s + psl) % capacity(); // Median search
size_t n = 0;
// Loop while there is a value and its psl is greater than our probe
while (_alloc[i].value && _alloc[i].psl <= psl) {
if (_equal(*_alloc[i].value, val)) {
// Check the first element;
if (_alloc[i].psl >= psl && _alloc[i].value) {
if (*_alloc[i].value == val) {
return iterator(this, i);
}
i = (i + 1) % capacity(); ++psl;
}
// Loop while there is a value and its psl is greater than our probe
while (true) {
++n;
size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow
size_t i1 = (i + n) % capacity();
int p0 = psl - n, p1 = psl + n;
bool c0 = false, c1 = false;
if ((c0 = (p0 > 0 && _alloc[i0].psl >= p0)) && _alloc[i0].value) {
if (*_alloc[i0].value == val) {
return iterator(this, i);
}
}
if ((c1 = (_alloc[i1].psl >= p1)) && _alloc[i1].value) {
if (*_alloc[i1].value == val) {
return iterator(this, i);
}
}
if (not(c0 or c1)) {
break;
}
}
return iterator(this, npos);
@@ -217,14 +257,14 @@ public:
}
_alloc[i].value = nullopt;
_sumpsl -= _alloc[i].psl;
--_size;
size_t p = i;
while (_alloc[i = (i + 1) % capacity()].value) {
size_t psl = _alloc[i].psl;
if (psl == 0) break;
if (_alloc[i].psl == 0) break;
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
_alloc[p].psl = psl - 1;
--_alloc[p].psl, --_sumpsl;
p = i;
}
}
@@ -316,10 +356,11 @@ private:
}
allocation<node, alloc_t> _alloc;
hash_t _hash;
hash_t _hash;
equal_t _equal;
size_t _size;
double _load;
size_t _size;
size_t _sumpsl;
double _load;
};
}

View File

@@ -16,12 +16,32 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_RENDERERS_OPENGL_LEGACY_H
#define FENNEC_RENDERERS_OPENGL_LEGACY_H
#ifndef FENNEC_CORE_SYSTEM_H
#define FENNEC_CORE_SYSTEM_H
#include <fennec/langproc/strings/string.h>
/*
* This should be implemented using the OpenGL ES 2.0 profile
* https://registry.khronos.org/OpenGL/specs/es/2.0/es_full_spec_2.0.pdf
*/
namespace fennec
{
#endif // FENNEC_RENDERERS_OPENGL_LEGACY_H
class system {
public:
using tick_f = void (*)(system*, double);
using frame_f = void (*)(system*, size_t);
const string name;
const tick_f tick;
const frame_f frame;
system(const cstring& name, tick_f tick, frame_f frame)
: name(name), tick(tick), frame(frame) {
}
virtual ~system() = default;
virtual void init() = 0;
virtual void shutdown() = 0;
};
}
#endif // FENNEC_CORE_SYSTEM_H

View File

@@ -16,9 +16,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#include <stdio.h>
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H

View File

@@ -16,14 +16,14 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_IO_FILE_H
#define FENNEC_FPROC_IO_FILE_H
#ifndef FENNEC_LANGPROC_IO_FILE_H
#define FENNEC_LANGPROC_IO_FILE_H
#include <fennec/fproc/filesystem/path.h>
#include <fennec/langproc/filesystem/path.h>
#include <fennec/fproc/strings/cstring.h>
#include <fennec/fproc/strings/string.h>
#include <fennec/fproc/strings/wstring.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/langproc/strings/wstring.h>
namespace fennec
{
@@ -34,7 +34,7 @@ namespace fennec
/// fmode_binary and fmode_wide are independent of the other modes
///
/// \details Valid Flag Combinations
/// <table width="100%" class="fieldtable" id="table_fennec_fproc_io_fmode">
/// <table width="100%" class="fieldtable" id="table_fennec_LANGPROC_io_fmode">
/// <tr><th style="vertical-align: top">Flags
/// <th style="vertical-align: top">Description
///
@@ -301,4 +301,4 @@ private:
}
#endif // FENNEC_FPROC_IO_FILE_H
#endif // FENNEC_LANGPROC_IO_FILE_H

View File

@@ -16,10 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_IO_PATH_H
#define FENNEC_FPROC_IO_PATH_H
#ifndef FENNEC_LANGPROC_IO_PATH_H
#define FENNEC_LANGPROC_IO_PATH_H
#include <fennec/fproc/strings/string.h>
#include <fennec/langproc/strings/string.h>
namespace fennec
{
@@ -233,4 +233,4 @@ private:
}
#endif // FENNEC_FPROC_IO_PATH_H
#endif // FENNEC_LANGPROC_IO_PATH_H

View File

@@ -16,10 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_CSTRING_H
#define FENNEC_FPROC_STRINGS_CSTRING_H
#ifndef FENNEC_LANGPROC_STRINGS_CSTRING_H
#define FENNEC_LANGPROC_STRINGS_CSTRING_H
#include <fennec/fproc/strings/detail/_ctype.h>
#include <fennec/langproc/strings/detail/_ctype.h>
#include <fennec/memory/detail/_string.h>
#include <fennec/lang/assert.h>
@@ -337,4 +337,4 @@ struct hash<cstring> : hash<byte_array> {
}
#endif // FENNEC_FPROC_STRINGS_CSTRING_H
#endif // FENNEC_LANGPROC_STRINGS_CSTRING_H

View File

@@ -16,10 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#include <ctype.h>
#include <wctype.h>
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H

View File

@@ -16,9 +16,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
#include <locale.h>
#endif // FENNEC_FPROC_STRINGS_DETAIL_CTYPE_H
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H

View File

@@ -16,10 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_LOCALE_H
#define FENNEC_FPROC_STRINGS_LOCALE_H
#ifndef FENNEC_LANGPROC_STRINGS_LOCALE_H
#define FENNEC_LANGPROC_STRINGS_LOCALE_H
#include <fennec/fproc/strings/detail/_locale.h>
#include <fennec/langproc/strings/detail/_locale.h>
namespace fennec
{
@@ -41,4 +41,4 @@ using ::localeconv;
}
#endif // FENNEC_FPROC_STRINGS_LOCALE_H
#endif // FENNEC_LANGPROC_STRINGS_LOCALE_H

View File

@@ -16,11 +16,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_STRING_H
#define FENNEC_FPROC_STRINGS_STRING_H
#ifndef FENNEC_LANGPROC_STRINGS_STRING_H
#define FENNEC_LANGPROC_STRINGS_STRING_H
#include <fennec/fproc/strings/detail/_ctype.h>
#include <fennec/fproc/strings/cstring.h>
#include <fennec/langproc/strings/detail/_ctype.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/lang/assert.h>
@@ -433,4 +433,4 @@ struct hash<string> : hash<byte_array> {
}
#endif // FENNEC_FPROC_STRINGS_STRING_H
#endif // FENNEC_LANGPROC_STRINGS_STRING_H

View File

@@ -16,10 +16,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_STRINGS_wcstring_H
#define FENNEC_FPROC_STRINGS_wcstring_H
#ifndef FENNEC_LANGPROC_STRINGS_wcstring_H
#define FENNEC_LANGPROC_STRINGS_wcstring_H
#include <fennec/fproc/strings/detail/_ctype.h>
#include <fennec/langproc/strings/detail/_ctype.h>
#include <fennec/memory/detail/_string.h>
#include <fennec/lang/assert.h>
@@ -323,4 +323,4 @@ private:
}
#endif // FENNEC_FPROC_STRINGS_wcstring_H
#endif // FENNEC_LANGPROC_STRINGS_wcstring_H

View File

@@ -16,11 +16,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_FPROC_wstringS_wstring_H
#define FENNEC_FPROC_wstringS_wstring_H
#ifndef FENNEC_LANGPROC_wstringS_wstring_H
#define FENNEC_LANGPROC_wstringS_wstring_H
#include <fennec/fproc/strings/detail/_ctype.h>
#include <fennec/fproc/strings/wcstring.h>
#include <fennec/langproc/strings/detail/_ctype.h>
#include <fennec/langproc/strings/wcstring.h>
#include <fennec/lang/assert.h>
@@ -415,4 +415,4 @@ private:
}
#endif // FENNEC_FPROC_wstringS_wstring_H
#endif // FENNEC_LANGPROC_wstringS_wstring_H

View File

@@ -532,24 +532,58 @@ public:
_capacity = n;
}
///
/// \brief Reallocate the block with a new size.
/// Contents are copied to the new allocation.
constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) {
callocate(n, align);
}
// Access ==============================================================================================================
value_t* old = _data;
_data = _alloc.allocate(n);
fennec::memcpy(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
if (n > _capacity) {
fennec::memset(static_cast<void*>(_data + _capacity), 0, n - _capacity);
}
_alloc.deallocate(old);
_capacity = n;
}
// Access ==============================================================================================================
constexpr value_t& operator[](size_t i) {
assertd(i < size(), "Array Out of Bounds");
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
}
constexpr value_t operator[](size_t i) const requires is_fundamental_v<value_t> {
assertd(i < size(), "Array Out of Bounds");
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
}
constexpr const value_t& operator[](size_t i) const {
assertd(i < size(), "Array Out of Bounds");
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
}
value_t* begin() {
return _data;
}
value_t* end() {
return _data + capacity();
}
const value_t* begin() const {
return _data;
}
const value_t* end() const {
return _data + capacity();
}
// Modification ========================================================================================================

View File

@@ -19,7 +19,7 @@
#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_H
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H
#include <fennec/fproc/strings/string.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>

View File

@@ -19,7 +19,7 @@
#ifndef FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#include <fennec/fproc/strings/string.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>

View File

@@ -20,8 +20,8 @@
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#include <fennec/containers/list.h>
#include <fennec/fproc/strings/cstring.h>
#include <fennec/fproc/strings/string.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>

View File

@@ -20,7 +20,7 @@
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H
#include <fennec/containers/optional.h>
#include <fennec/fproc/strings/string.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/platform/interface/fwd.h>
namespace fennec

View File

@@ -19,4 +19,170 @@
#ifndef FENNEC_RENDERERS_INTERFACE_RENDERER_H
#define FENNEC_RENDERERS_INTERFACE_RENDERER_H
#include <fennec/containers/dynarray.h>
#include <fennec/lang/types.h>
#include <fennec/langproc/strings/cstring.h>
#include <fennec/math/matrix.h>
#include <fennec/math/scalar.h>
#include <fennec/math/ext/quaternion.h>
/*
* Some ramblings on deciding what objects are needed to support the features in PLANNING.md
*
*
* Definitions:
* Static Mesh -> A mesh whose number of vertices and attributes does not change after creation
* Object -> A static mesh instance
* Skeletal Mesh -> A static mesh with support for skinned rigs
* Animation -> A set of keys for a skeletal mesh
* Puppet -> A skeletal mesh instance
* Static Object -> An object whose transform does not change after scene start
* Dynamic Object -> An object whose transform can change after scene start, all puppets must be dynamic objects
* Static Light -> A light whose transform does not change after scene start. Other attributes may change, which will
* be specified per light
* Dynamic Light -> A light whose transform can change after scene start, including all attributes
*
* Static mesh rendering
* Skeletal mesh rendering
* Lights with or without shadows (PCSS for soft shadowing)
* - Sun Light
* - Skybox
* - Point Light
* - Spotlight
* - Area light
* Post-Processing
*
* Materials
*/
namespace fennec
{
class renderer3d {
public:
// These refer to assets
// texture -> 8-bit type, 24-bit id (256, 16,777,216)
// mesh -> 32-bit id (4,294,967,296)
// skeleton -> 32-bit id (4,294,967,296)
// animation -> 32-bit id (4,294,967,296)
// shader -> 32-bit id (4,294,967,296)
// model -> 8-bit flag, 24-bit id (8, 16,777,216)
// puppet -> 32-bit id (4,294,967,296)
// light -> 8-bit type, 24-bit id (256, 16,777,216)
// material -> 32-bit id (4,294,967,296)
// TYPEDEFS & CONSTANTS ================================================================================================
using uid_t = uint32_t;
static constexpr uid_t null = -1;
static constexpr uint_t max_bone_weights = 8;
// ENUMS ===============================================================================================================
enum format_ : uint8_t {
format_r = 0,
format_rg,
format_rgb,
format_rgba,
format_shadow, // TODO: decide whether end-users may create shadow buffers
format_count,
format_last = format_count - 1,
};
enum texture_ : uint8_t {
texture_2d = 0,
texture_3d,
texture_cubemap,
};
enum light_ : uint8_t {
light_sun = 0,
light_sky,
light_point,
light_spot,
light_area,
};
enum iterp_ : uint8_t {
iterp_step = 0,
iterp_linear,
iterp_spherical,
iterp_cubic,
};
// STRUCTURES ==========================================================================================================
struct mesh_vertex {
vec3 location;
vec3 normal;
vec3 tangent;
vec2 uv;
};
struct skin_vertex {
vec3 location;
vec3 normal;
vec3 tangent;
vec2 uv;
uint32_t bones[max_bone_weights];
uint32_t weights[max_bone_weights];
};
struct bone {
mat4 localSpace; // I was going to use quaternions, but Assimp, glTF, FBX, Unity, Unreal, and Godot all use matrices
};
struct skeleton {
mat4 root;
uint boneStart, boneEnd; // APIs job to figure out how to store bones, should be in a SSBO regardless of API
};
// Wrapper for animation keys
template<typename ValueT>
struct key {
double time;
ValueT val;
uint8_t mode;
};
// Wrapper for a track, essentially the keyframes for a single bone
struct track {
uint posStart, posEnd; // APIs job to figure out how to store keys, should be in a SSBO regardless of API
uint rotStart, rotEnd;
uint sclStart, sclEnd;
};
struct animation {
uint trkStart, trkEnd; // APIs job to figure out how to store tracks, should be in a SSBO regardless of API
};
// FUNCTIONS ===========================================================================================================
virtual uid_t create_mesh(const dynarray<uint32_t>& indices, const dynarray<mesh_vertex>& vertices) = 0;
virtual void release_mesh(uid_t id);
// TODO: virtual uid_t create_skeleton()
// TODO: virtual uid_t create_shader()
virtual uid_t create_texture(uint8_t type, uint8_t format, bool hdr) = 0;
virtual void release_texture(uid_t);
// TODO: virtual uid_t create_light()
virtual ~renderer3d() = default;
private:
};
}
#endif // FENNEC_RENDERERS_INTERFACE_RENDERER_H

View File

@@ -29,6 +29,8 @@
* - ARB_compute_shader
* - ARB_shader_image_load_store
* - ARB_texture_cube_map_array
*
* This will support all mobile devices since 2012
*/
#endif // FENNEC_RENDERERS_OPENGL_FALLBACK_H

View File

@@ -29,6 +29,8 @@
* - ARB_compute_shader
* - ARB_shader_image_load_store
* - ARB_texture_cube_map_array
*
* This will support >91.31% of devices on Steam, including all Desktop GPUs and iGPUs since 2012
*/
#endif // FENNEC_RENDERERS_OPENGL_MODERN_H

View File

@@ -0,0 +1,69 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
#ifndef FENNEC_SCENE_COMPONENT_H
#define FENNEC_SCENE_COMPONENT_H
#include <fennec/containers/dynarray.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h>
namespace fennec
{
class component {
public:
using component_create = component (*)(size_t);
using component_find = component* (*)(size_t);
using component_erase = void (*)(size_t);
struct type {
string name;
component_create create;
component_find find;
component_erase erase;
};
private:
static dynarray<type>& _type_list() {
static dynarray<type> type_list;
return type_list;
}
static void _register_type(uint64_t id, const cstring& name, component_create create, component_find find, component_erase erase) {
dynarray<type>& type_list = _type_list();
if (id > type_list.size()) {
type_list.resize(id + 1);
}
type_list[id] = { name, create, find, erase };
}
public:
template<typename ComponentT>
static void register_type(const cstring& name, component_create create, component_find find, component_erase erase) {
component::_register_type(typeuuid<ComponentT>(), name, create, find, erase);
}
static const dynarray<type>& type_list() {
return _type_list();
}
};
}
#endif // FENNEC_SCENE_COMPONENT_H

View File

@@ -0,0 +1,60 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
#ifndef FENNEC_CORE_SCENE_H
#define FENNEC_CORE_SCENE_H
#include <fennec/containers/rdtree.h>
#include <fennec/langproc/strings/string.h>
namespace fennec
{
class scene : public rdtree<string> {
public:
size_t operator[](const cstring& name) const {
list<size_t> parse;
parse.push_back(root);
while (not parse.empty()) {
if (*_data[parse.front()].value == name) {
return parse.front();
}
parse.push_back(child(parse.front()));
parse.push_back(next(parse.front()));
parse.pop_front();
}
return npos;
}
size_t operator[](const string& name) const {
list<size_t> parse;
parse.push_back(root);
while (not parse.empty()) {
if (*_data[parse.front()].value == name) {
return parse.front();
}
parse.push_back(child(parse.front()));
parse.push_back(next(parse.front()));
parse.pop_front();
}
return npos;
}
};
}
#endif // FENNEC_CORE_SCENE_H