- Changed directory structure significantly, moving gfx api implementations to fennec/renderers

- Began new overarching window interface
 - Began outlining renderer interfaces
 - Began a binary tree implementation in bintree.h, this will act as a generalized binary tree, then red-black tree will be implemented on top of it for sequences (ordered sets)
This commit is contained in:
2025-08-28 00:01:46 -04:00
parent e1eaf97961
commit 992a02db3e
35 changed files with 791 additions and 686 deletions

View File

@@ -21,18 +21,6 @@ cmake_minimum_required(VERSION 3.30)
project(fennec) project(fennec)
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
# External dependencies should be loaded here
add_subdirectory(external/cpptrace)
include("${FENNEC_SOURCE_DIR}/cmake/sdl.cmake")
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_C_STANDARD 23)
add_custom_target(fennec-dependencies
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
COMMENT "Running dependencies."
)
macro(fennec_add_sources) macro(fennec_add_sources)
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN}) list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
endmacro() endmacro()
@@ -45,10 +33,26 @@ macro(fennec_add_link_libraries)
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN}) list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
endmacro() endmacro()
macro(fennec_add_shared_libraries)
list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN})
endmacro()
macro(fennec_add_link_options) macro(fennec_add_link_options)
list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN}) list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN})
endmacro() endmacro()
# External dependencies should be loaded here
add_subdirectory(external/cpptrace)
include("${FENNEC_SOURCE_DIR}/cmake/sdl.cmake")
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_C_STANDARD 23)
add_custom_target(fennec-dependencies
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
COMMENT "Running dependencies."
)
# include scripts # include scripts
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake") include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake") include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
@@ -90,6 +94,13 @@ add_library(fennec STATIC
include/fennec/scene/component.h include/fennec/scene/component.h
# Renderers ============================================================================================================
include/fennec/renderers/interface/forward.h
include/fennec/renderers/interface/gfxcontext.h
include/fennec/renderers/interface/gfxsubpass.h
# CONTAINERS =========================================================================================================== # CONTAINERS ===========================================================================================================
include/fennec/containers/containers.h include/fennec/containers/containers.h
@@ -130,7 +141,7 @@ add_library(fennec STATIC
include/fennec/lang/type_sequences.h include/fennec/lang/type_sequences.h
include/fennec/lang/type_traits.h include/fennec/lang/type_traits.h
include/fennec/lang/type_transforms.h include/fennec/lang/type_transforms.h
include/fennec/lang/typeuuid.h include/fennec/lang/typed.h
include/fennec/lang/types.h include/fennec/lang/types.h
include/fennec/lang/utility.h include/fennec/lang/utility.h
include/fennec/lang/integer.h include/fennec/lang/integer.h
@@ -218,13 +229,13 @@ add_library(fennec STATIC
include/fennec/platform/interface/fwd.h include/fennec/platform/interface/fwd.h
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
include/fennec/platform/interface/window.h
# EXTRA SOURCES ======================================================================================================== # EXTRA SOURCES ========================================================================================================
${FENNEC_EXTRA_SOURCES} ${FENNEC_EXTRA_SOURCES}
include/fennec/platform/interface/window.h include/fennec/containers/bintree.h
include/fennec/platform/sdl/sdlwindow.h
) )
add_dependencies(fennec metaprogramming fennec-dependencies) add_dependencies(fennec metaprogramming fennec-dependencies)
@@ -240,14 +251,16 @@ target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not comp
target_link_libraries(fennec PRIVATE target_link_libraries(fennec PRIVATE
${FENNEC_LINK_LIBRARIES} ${FENNEC_LINK_LIBRARIES}
${FENNEC_SHARED_LIBRARIES}
cpptrace::cpptrace cpptrace::cpptrace
SDL3::SDL3-shared
) )
add_custom_command(TARGET fennec POST_BUILD foreach (_LIB IN ITEMS ${FENNEC_SHARED_LIBRARIES})
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:SDL3::SDL3-shared> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} add_custom_command(TARGET fennec POST_BUILD
) COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:${_LIB}> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
endforeach ()
# DOXYGEN ============================================================================================================== # DOXYGEN ==============================================================================================================

View File

@@ -18,4 +18,13 @@
set(SDL_AUDIO OFF) set(SDL_AUDIO OFF)
set(SDL_RENDER OFF) set(SDL_RENDER OFF)
add_subdirectory(external/SDL) add_subdirectory(${FENNEC_SOURCE_DIR}/external/SDL)
fennec_add_sources(
include/fennec/platform/sdl/sdlwindow.h
)
fennec_add_shared_libraries(
SDL3::SDL3-shared
)

View File

@@ -0,0 +1,299 @@
// =====================================================================================================================
// 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 bintree.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_BINTREE_H
#define FENNEC_CONTAINERS_BINTREE_H
#include <fennec/containers/dynarray.h>
#include <fennec/containers/list.h>
#include <fennec/containers/optional.h>
#include <fennec/math/exponential.h>
#include <fennec/memory/allocator.h>
namespace fennec
{
template<typename TypeT, class AllocT>
struct bintree {
// Definitions =========================================================================================================
protected:
struct node;
public:
using value_t = TypeT;
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
static constexpr size_t root = 0;
static constexpr size_t npos = -1;
protected:
struct node {
optional<value_t> value;
size_t parent, left, right;
size_t depth;
constexpr node()
: value(nullopt)
, parent(npos), left(npos), right(npos)
, depth(0) {
}
template<typename...ArgsT>
constexpr node(size_t p, size_t l, size_t r, size_t d, ArgsT&&...args)
: value(fennec::forward<ArgsT>(args)...)
, parent(p), left(l), right(r)
, depth(d) {
}
constexpr ~node() {
parent = npos;
left = npos;
right = npos;
depth = npos;
}
};
using table_t = allocation<node, alloc_t>;
using freed_t = list<size_t, alloc_t>;
// Navigation ==========================================================================================================
public:
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The parent of node `i`
constexpr size_t parent(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].parent;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The left child of node `i`
constexpr size_t left(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].left;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The right child of node `i`
constexpr size_t right(size_t i) const {
if (i >= _table.size()) {
return false;
}
return _table[i].right;
}
///
/// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The depth of node `i`
constexpr size_t depth(size_t i) const {
if (i >= _table.size()) {
return npos;
}
return _table[i].depth;
}
// Access ==============================================================================================================
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr value_t* operator[](size_t i) {
if (i >= _table.size()) {
return nullptr;
}
return _table[i] ? &*_table[i] : nullptr;
}
///
/// \details Const Access, \f$O(1)\f$
/// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i`
constexpr const value_t* operator[](size_t i) const {
if (i >= _table.size()) {
return nullptr;
}
return _table[i] ? &*_table[i] : nullptr;
}
// Modifiers ===========================================================================================================
///
/// \brief Move Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, value_t&& val) {
return this->_insert_left(p, fennec::forward<value_t>(val));
}
///
/// \brief Copy Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the copy assignment operator is used instead
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
constexpr size_t insert_left(size_t p, const value_t& val) {
return this->_insert_left(p,, val);
}
///
/// \brief Move Left Insertion, constructs a new node as the left child of `p`
/// \details If the left node of `p` already exists, the move assignment operator is used instead
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
template<typename...ArgsT>
constexpr size_t emplace_left(size_t p, ArgsT&&...args) {
return this->_insert_left(p, fennec::forward<ArgsT>(args)...);
}
///
/// \brief Perform a Left Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_left(size_t i) {
if (i >=_table.size()) {
return;
}
size_t l = i;
size_t p = parent(l);
size_t r = right(l);
if (p == npos) {
_root = r;
} else if (l == _table[p].left) {
_table[p].left = r;
} else {
_table[p].right = r;
}
_table[l].parent = r;
_table[l].right = _table[r].left;
_table[r].parent = p;
_table[r].left = l;
}
///
/// \brief Perform a Right Tree Rotation at `i`
/// \param i The root node for the rotation
constexpr void rotate_right(size_t i) {
if (i >=_table.size()) {
return;
}
size_t r = i;
size_t p = parent(r);
size_t l = left(r);
if (p == npos) {
_root = l;
} else if (r == _table[p].left) {
_table[p].left = l;
} else {
_table[p].right = l;
}
_table[r].parent = l;
_table[r].left = _table[l].right;
_table[l].parent = p;
_table[l].right = r;
}
protected:
table_t _table;
freed_t _freed;
size_t _root, _size;
constexpr void _next_free() {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
_freed.pop_front();
}
if (i >= _table.size()) {
_table.reallocate(2 * fennec::max(_table.size(), 4));
}
}
template<typename...ArgsT>
constexpr size_t _insert_left(size_t p, ArgsT&&...args) {
size_t i = left(p);
if (i == npos) {
i = _next_free();
_table[i].value.emplace(fennec::forward<ArgsT>(args)...);
} else {
size_t d = 1;
if (p != npos) {
d = depth(p) + 1;
_table[p].left = i;
}
fennec::construct(&_table[i], p, npos, npos, d);
}
}
template<typename...ArgsT>
constexpr size_t _insert_right(size_t p, ArgsT&&...args) {
size_t i = right(p);
if (i == npos) {
i = _next_free();
_table[i].value.emplace(fennec::forward<ArgsT>(args)...);
if (p == npos || _root == npos) {
_root = i;
}
} else {
size_t d = 1;
if (p != npos) {
d = depth(p) + 1;
_table[p].right = i;
}
fennec::construct(&_table[i], p, npos, npos, d);
}
}
};
}
#endif // FENNEC_CONTAINERS_BINTREE_H

View File

@@ -1,586 +0,0 @@
// =====================================================================================================================
// 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 multiset.h
/// \brief A header containing the definition for a set of repeating values
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_MULTISET_H
#define FENNEC_CONTAINERS_MULTISET_H
// https://programming.guide/robin-hood-hashing.html
#include <fennec/containers/optional.h>
#include <fennec/containers/multiset.h>
#include <fennec/lang/compare.h>
#include <fennec/math/ext/primes.h>
#include <fennec/memory/allocator.h>
#include <fennec/lang/hashing.h>
namespace fennec
{
///
///
/// \brief A Data Structure that defines a set of elements that may repeat
/// \details
/// | Property | Value |
/// |:----------:|:----------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogenous | ✅ |
/// | distinct | ⛔ |
/// | ordered | ⛔ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
///
/// \tparam TypeT The type to contain
template<typename TypeT, class Hash = hash<TypeT>, class Equals = equality<TypeT>, class Alloc = allocator<TypeT>>
struct multiset {
// Definitions =========================================================================================================
public:
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>;
using hash_t = Hash;
using equal_t = Equals;
using elem_t = TypeT;
class iterator;
class value_iterator;
static constexpr size_t npos = -1;
static constexpr double default_load = 0.8;
private:
struct node {
optional<elem_t> value;
int psl;
constexpr node() = default;
constexpr ~node() = default;
};
// Constructors ========================================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Default Constructor, initializes empty multiset
constexpr multiset()
: _alloc()
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
};
///
/// \brief Hash Copy Constructor, initializes empty multiset with a hash
constexpr multiset(const hash_t& hash)
: _alloc()
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Hash Move Constructor, initializes empty multiset with a hash
constexpr multiset(hash_t&& hash) noexcept
: _alloc()
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Alloc Copy Constructor, initializes empty multiset with an allocator
constexpr multiset(const alloc_t& alloc)
: _alloc(alloc)
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Alloc Move Constructor, initializes empty multiset with an allocator
constexpr multiset(alloc_t&& alloc) noexcept
: _alloc(alloc)
, _hash()
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Hash Alloc Copy Constructor, initializes empty multiset with a hash and allocator
constexpr multiset(const hash_t& hash, const alloc_t& alloc)
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Hash Copy Alloc Move Constructor, initializes empty multiset with a hash and allocator
constexpr multiset(const hash_t& hash, alloc_t&& alloc) noexcept
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Hash Move Alloc Move Constructor, initializes empty multiset with a hash and allocator
constexpr multiset(hash_t&& hash, alloc_t&& alloc) noexcept
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Hash Move Alloc Copy Constructor, initializes empty multiset with a hash and allocator
constexpr multiset(hash_t&& hash, const alloc_t& alloc) noexcept
: _alloc(alloc)
, _hash(hash)
, _size(0)
, _sumpsl(0)
, _load(default_load) {
}
///
/// \brief Set Copy Constructor
/// \param multiset Set to copy
constexpr multiset(const multiset& multiset)
: _alloc( multiset._alloc)
, _hash( multiset._hash)
, _size( multiset._size)
, _sumpsl( multiset._sumpsl)
, _load( multiset._load) {
}
///
/// \brief Set Move Constructor
/// \param multiset Set to move
constexpr multiset(multiset&& multiset) noexcept
: _alloc(fennec::move( multiset._alloc))
, _hash(fennec::move( multiset._hash))
, _size(fennec::move( multiset._size))
, _sumpsl( multiset._sumpsl)
, _load( multiset._load) {
}
///
/// \brief Destructor, destructs all elements and releases the allocation
constexpr ~multiset() {
for (size_t i = 0; i < capacity(); ++i) {
_alloc[i].value = nullopt;
}
}
/// @}
// Properties ==========================================================================================================
/// \name Properties
/// @{
///
/// \returns Size of the multiset in elements
constexpr size_t size() const {
return _size;
}
///
/// \returns `true` when the set is empty, `false` otherwise
constexpr bool empty() const {
return _size == 0;
}
///
/// \returns Capacity of the multiset in elements
constexpr size_t capacity() const {
return _alloc.capacity();
}
/// @}
// Access ==============================================================================================================
/// \name Access
/// @{
///
/// \brief Find an Element
/// \param val Value to find
/// \returns An iterator at the location of the first instance of `value`
constexpr iterator find(const elem_t& val, size_t c = 0) const {
if (capacity() == 0) {
return end();
}
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;
// Check the first element;
if (_alloc[i].psl >= psl && _alloc[i].value) {
if (*_alloc[i].value == val) {
return iterator(this, i);
}
}
// Loop while there is a value and its psl is greater than our probe
while (c > 0) {
++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 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
if (c0 && _alloc[i0].value) {
if (*_alloc[i0].value == val) {
if (c-- == 0) {
return iterator(this, i0);
}
}
}
if (c1 && _alloc[i1].value) {
if (*_alloc[i1].value == val) {
if (c-- == 0) {
return iterator(this, i1);
}
}
}
if (not(c0 or c1)) {
break;
}
}
return iterator(this, npos);
}
///
/// \brief Check if a multiset contains a value
/// \param val Value to check
/// \returns `true` if `val` can be found, `false` otherwise
constexpr bool contains(const elem_t& val) const {
return this->find(val) != end();
}
///
/// \brief Iterator Access
/// \param it Location to access
/// \returns A pointer to the element, `nullptr` if not found.
/// The value should not be changed in a manner that will change the hash of the element.
constexpr elem_t* at(const iterator& it) {
if (it == end()) {
return nullptr;
}
if (not _alloc[it._i].value) {
return nullptr;
}
return &*_alloc[it._i].value;
}
///
/// \brief Iterator Const Access
/// \param it Location to access
/// \returns A const-qualified pointer to the element, `nullptr` if not found.
constexpr const elem_t* at(const iterator& it) const {
if (not _alloc[it._i].value) return nullptr;
return &*_alloc[it._i].value;
}
/// @}
// Modifiers ===========================================================================================================
/// \name Modifiers
/// @{
///
/// \brief Move Insertion
/// \param val Value to insert
constexpr void insert(elem_t&& val) {
this->_insert(fennec::forward<elem_t>(val));
}
///
/// \brief Copy Insertion
/// \param val Value to insert
constexpr void insert(const elem_t& val) {
this->_insert(val);
}
///
/// \brief Emplace Insertion
/// \tparam ArgsT Argument types
/// \param args Arguments to construct with
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
this->_insert(fennec::forward<ArgsT>(args)...);
}
///
/// \brief Element Erase
/// \param it Location to erase
constexpr void erase(iterator it) {
size_t i = it._i;
if (i >= capacity()) {
return;
} // These are separated due to compilers being inconsistent
if (not _alloc[i].value) {
return;
}
_alloc[i].value = nullopt;
_sumpsl -= _alloc[i].psl;
--_size;
size_t p = i;
while (_alloc[i = (i + 1) % capacity()].value) {
if (_alloc[i].psl == 0) break;
fennec::swap(_alloc[i - 1].value, _alloc[i].value);
--_alloc[p].psl, --_sumpsl;
p = i;
}
}
///
/// \brief Element Erase
/// \param val Value to erase
constexpr void erase(const elem_t& val) {
this->erase(this->find(val));
}
/// @}
// ITERATOR ============================================================================================================
/// \name Iteration
/// @{
///
/// \brief C++ Iterator Specification `begin()`
/// \returns An iterator for all elements of the set in no particular order
constexpr iterator begin() const {
iterator it(this, 0);
if (not _alloc[it._i].value) {
++it;
}
return it;
}
///
/// \brief C++ Iterator Specification `end()`
/// \returns An iterator representing the end of the set
constexpr iterator end() const {
return iterator(this, npos);
}
/// @}
///
/// \brief Class for Iterating the Set
class iterator {
public:
constexpr ~iterator() {
_set = nullptr;
}
// prefix operator
constexpr iterator& operator++() {
while (++_i < _set->capacity()) {
if (_set->_alloc[_i].value) {
return *this;
}
}
_i = npos;
return *this;
}
constexpr iterator operator++(int) {
iterator prev = *this;
this->operator++();
return prev;
}
constexpr const elem_t& operator*() const {
return *_set->_alloc[_i].value;
}
constexpr const elem_t* operator->() const {
if (not _set->_alloc[_i].value) return nullptr;
return &*_set->_alloc[_i].value;
}
constexpr bool operator==(const iterator& it) const {
return _set == it._set and _i == it._i;
}
constexpr bool operator!=(const iterator& it) const {
return _set != it._set or _i != it._i;
}
private:
const multiset* _set;
size_t _i;
friend multiset;
constexpr iterator(const multiset* multiset, size_t i)
: _set(multiset)
, _i(i) {
}
};
class value_iterator {
public:
constexpr ~value_iterator() {
_set = nullptr;
}
// prefix operator
constexpr value_iterator& operator++() {
while (_psl <= _set->_alloc[_i].psl) {
if (not _set->_alloc[_i].value) {
break;
}
}
_i = npos;
return *this;
}
constexpr value_iterator operator++(int) {
value_iterator prev = *this;
this->operator++();
return prev;
}
constexpr const elem_t& operator*() const {
return *_set->_alloc[_i].value;
}
constexpr const elem_t* operator->() const {
if (not _set->_alloc[_i].value) return nullptr;
return &*_set->_alloc[_i].value;
}
constexpr bool operator==(const iterator& it) const {
return _set == it._set and _i == it._i;
}
constexpr bool operator!=(const iterator& it) const {
return _set != it._set or _i != it._i;
}
private:
const multiset* _set;
size_t _i;
int _psl;
elem_t _value;
friend multiset;
constexpr value_iterator(const multiset* multiset, size_t i, int psl, const elem_t& value)
: _set(multiset)
, _i(i)
, _value(value) {
}
};
// PRIVATE =============================================================================================================
private:
constexpr void _expand() {
multiset cpy; // Create a new multiset
cpy._alloc.callocate(
fennec::next_prime2(_alloc.capacity())
);
// rehash
for (size_t i = 0; i < capacity(); ++i) {
if (_alloc[i].value) {
cpy.insert(fennec::move(*_alloc[i].value));
}
}
// Swap buffers
fennec::swap(_alloc, cpy._alloc);
}
template<typename...ArgsT>
constexpr void _insert(ArgsT&&...args) {
if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
_expand();
}
elem_t value(fennec::forward<ArgsT>(args)...);
size_t i = _hash(value) % capacity(); // Initial search index
int psl = 0;
while (_alloc[i].value) { // Search for empty cell
if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted
return;
}
if (psl > _alloc[i].psl) { // When psl is higher, swap
_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);
_sumpsl += (_alloc[i].psl = psl);
++_size;
}
allocation<node, alloc_t> _alloc;
hash_t _hash;
equal_t _equal;
size_t _size;
size_t _sumpsl;
float _load;
};
}
#endif // FENNEC_CONTAINERS_SET_H

View File

@@ -294,9 +294,35 @@ public:
/// \name Modifiers /// \name Modifiers
/// @{ /// @{
///
/// \brief Emplace Assignment, Move overload
/// \param val The object to take ownership of
constexpr T& emplace(T&& val) {
if (_set) {
_val = fennec::forward<T>(val);
} else {
fennec::construct(&_val, fennec::forward<T>(val));
_set = true;
}
return _val;
}
///
/// \brief Emplace Assignment, Copy overload
/// \param val The object to copy
constexpr T& emplace(const T& val) {
if (_set) {
_val = val;
} else {
fennec::construct(&_val, val);
_set = true;
}
return _val;
}
/// ///
/// \brief Emplace Assignment /// \brief Emplace Assignment
/// \val The optional to move /// \param args The arguments to construct with
template<typename...ArgsT> template<typename...ArgsT>
constexpr T& emplace(ArgsT&&...args) { constexpr T& emplace(ArgsT&&...args) {
if (_set) { if (_set) {

View File

@@ -58,7 +58,7 @@ public:
protected: protected:
struct node { struct node {
optional<TypeT> value; optional<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;

View File

@@ -20,7 +20,7 @@
#define FENNEC_CORE_EVENT_H #define FENNEC_CORE_EVENT_H
#include <fennec/lang/types.h> #include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h> #include <fennec/lang/typed.h>
namespace fennec namespace fennec
{ {

View File

@@ -22,8 +22,9 @@
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/langproc/strings/cstring.h> #include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h> #include <fennec/lang/typed.h>
#include <fennec/platform/interface/fwd.h> #include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/window.h>
/* /*
* This class should resemble the target platform as a whole. By itself, it will represent the OS, i.e. Linux, Windows, * This class should resemble the target platform as a whole. By itself, it will represent the OS, i.e. Linux, Windows,
@@ -64,6 +65,12 @@ public:
using shared_object = struct shared_object; using shared_object = struct shared_object;
using symbol = void*; using symbol = void*;
template<typename ctor>
struct driver {
int priority;
ctor constructor;
};
const string name; const string name;
virtual ~platform() = default; virtual ~platform() = default;
@@ -76,14 +83,21 @@ public:
virtual void initialize(); // Initialize Drivers and Contexts virtual void initialize(); // Initialize Drivers and Contexts
virtual void shutdown(); // Close Drivers and Contexts virtual void shutdown(); // Close Drivers and Contexts
// Platform level functions for retrieving driver and protocol contexts ================================================
// Window Management
using window_ctor = window* (*)(platform*, const window::config&);
using window_driver = driver<window_ctor>;
window* create_window(const window::config& config);
static void register_window_driver(window_driver&& driver);
protected: protected:
template<typename PlatformT> template<typename PlatformT>
explicit platform(const cstring& name, PlatformT* type) explicit platform(const cstring& name, PlatformT* type)
: typed(type) : typed(type)
, name(name) { , name(name) {
auto& globals = _get_globals(); assertf(singleton == nullptr, "Conflicting platform implementations!");
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions."); singleton = this;
globals.singleton = this;
} }
private: private:
@@ -92,31 +106,12 @@ private:
// Static Stuff ======================================================================================================== // Static Stuff ========================================================================================================
public: public:
template<typename ctor> static platform* instance() {
struct driver { return singleton;
int priority; }
ctor constructor;
};
struct global_context {
platform* singleton;
global_context()
: singleton(nullptr) {
}
};
private: private:
static global_context& _get_globals(); static platform* singleton;
public:
static const global_context& get_globals() {
return _get_globals();
}
static platform* instance() {
return _get_globals().singleton;
}
}; };
} }

View File

@@ -30,6 +30,7 @@
#ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H #ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H #define FENNEC_PLATFORM_INTERFACE_WINDOW_H
#include <fennec/lang/types.h> #include <fennec/lang/types.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
@@ -38,6 +39,8 @@ namespace fennec
class window { class window {
public: public:
virtual ~window() = default;
enum flags : uint8_t { enum flags : uint8_t {
fullscreen = 0x1 << 0, fullscreen = 0x1 << 0,
borderless = 0x1 << 1, borderless = 0x1 << 1,
@@ -49,8 +52,8 @@ public:
}; };
enum vsync { enum vsync {
off = 0, vsync_off = 0,
vsync = 1, vsync_on = 1,
adaptive_sync = -1, adaptive_sync = -1,
}; };
@@ -74,6 +77,8 @@ public:
// Properties ========================================================================================================== // Properties ==========================================================================================================
virtual bool running() = 0;
bool is_fullscreen() const { bool is_fullscreen() const {
return _config.flags & fullscreen; return _config.flags & fullscreen;
} }
@@ -110,13 +115,19 @@ public:
// Modifiers =========================================================================================================== // Modifiers ===========================================================================================================
virtual void set_fullscreen(bool) = 0; virtual void set_fullscreen(bool) = 0;
virtual void set_borderless(bool) = 0; virtual void set_borderless(bool) = 0;
virtual void grab_mouse(bool) = 0; virtual void grab_mouse(bool) = 0;
virtual void grab_keyboard(bool) = 0; virtual void grab_keyboard(bool) = 0;
virtual void set_title(const cstring&) = 0; virtual void set_title(const cstring&) = 0;
virtual void set_title(const string& str) = 0; virtual void set_title(const string&) = 0;
virtual void set_vsync_mode(int8_t) = 0; virtual void vsync(int8_t) = 0;
virtual void set_progress(bool, float) = 0;
// Graphics ============================================================================================================
virtual void begin_frame() = 0;
virtual void end_frame() = 0;
protected: protected:
window* _parent; window* _parent;

View File

@@ -31,11 +31,19 @@
#ifndef FENNEC_PLATFORM_SDL_SDLWINDOW_H #ifndef FENNEC_PLATFORM_SDL_SDLWINDOW_H
#define FENNEC_PLATFORM_SDL_SDLWINDOW_H #define FENNEC_PLATFORM_SDL_SDLWINDOW_H
#include <fennec/platform/interface/window.h>
namespace fennec namespace fennec
{ {
class sdlwindow : public window {
public:
private:
};
} }
#endif // FENNEC_PLATFORM_SDL_SDLWINDOW_H #endif // FENNEC_PLATFORM_SDL_SDLWINDOW_H

View File

@@ -0,0 +1,45 @@
// =====================================================================================================================
// 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 forward.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_INTERFACE_FORWARD_H
#define FENNEC_RENDERERS_INTERFACE_FORWARD_H
namespace fennec
{
class renderer; // Overarching rendering scheme
class gfxcontext; // Globals for an API's context
class gfxresourcepool; // Handles resource creation, allocation, and mapping
class gfxsubpass; // A subpass of the renderer, implements, for example, the steps of composing and lighting a deferred renderer
class gfxpipeline; // A user-defined pipeline, e.g. the Vulkan pipeline needed to render the G-Buffer
}
#endif // FENNEC_RENDERERS_INTERFACE_FORWARD_H

View File

@@ -0,0 +1,58 @@
// =====================================================================================================================
// 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 gfxcontext.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H
#define FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H
#include <fennec/renderers/interface/renderer.h>
namespace fennec
{
class gfxcontext {
public:
gfxcontext& operator=(const gfxcontext&) = delete;
gfxcontext& operator=(gfxcontext&&) = delete;
renderer* get_renderer() {
return _renderer;
}
protected:
renderer* _renderer;
gfxcontext(renderer* renderer);
private:
};
}
#endif // FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H

View File

@@ -0,0 +1,41 @@
// =====================================================================================================================
// 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 gfxsubpass.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H
#define FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H
namespace fennec
{
}
#endif // FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H

View File

@@ -0,0 +1,80 @@
// =====================================================================================================================
// 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 gfxcontext.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#include <fennec/lang/types.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/renderers/interface/forward.h>
namespace fennec
{
///
/// \brief Defines a renderer interface to implement different graphics APIs, e.g. OpenGL Vulkan
/// \details This represents the overarching renderer, and not any platform specific behaviour.
/// I.E. This acts as a proxy for creating API objects, but the behaviour of those objects
/// is defined elsewhere.
class renderer {
public:
enum texture_ : uint8_t {
texture_1d = 0,
texture_1d_array,
texture_2d,
texture_2d_array,
texture_multisample,
texture_multisample_array,
texture_cubemap,
texture_cubemap_array,
texture_3d,
};
using handle_t = uint32_t;
struct version_t {
uint8_t major, minor, patch;
string str;
};
const version_t version;
gfxcontext context;
gfxresourcepool resources;
handle_t add_subpass();
private:
};
}
#endif // FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H

View File

@@ -60,21 +60,21 @@ enum access_ : GLbitfield {
}; };
enum texture_ : GLenum { enum texture_ : GLenum {
TEX_1D = GL_TEXTURE_1D, TEX_1D = GL_TEXTURE_1D,
TEX_1D_V = GL_TEXTURE_1D_ARRAY, TEX_1D_ARRAY = GL_TEXTURE_1D_ARRAY,
TEX_2D = GL_TEXTURE_2D, TEX_2D = GL_TEXTURE_2D,
TEX_2D_V = GL_TEXTURE_2D_ARRAY, TEX_2D_ARRAY = GL_TEXTURE_2D_ARRAY,
TEX_2D_MS = GL_TEXTURE_2D_MULTISAMPLE, TEX_2D_MS = GL_TEXTURE_2D_MULTISAMPLE,
TEX_2D_MS_V = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, TEX_2D_MS_ARRAY = GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
TEX_RECT = GL_TEXTURE_RECTANGLE, TEX_RECT = GL_TEXTURE_RECTANGLE,
TEX_CUBEMAP = GL_TEXTURE_CUBE_MAP, TEX_CUBEMAP = GL_TEXTURE_CUBE_MAP,
TEX_CUBEMAP_V = GL_TEXTURE_CUBE_MAP_ARRAY, TEX_CUBEMAP_ARRAY = GL_TEXTURE_CUBE_MAP_ARRAY,
TEX_3D = GL_TEXTURE_3D, TEX_3D = GL_TEXTURE_3D,
TEX_BUFFER = GL_TEXTURE_BUFFER, TEX_BUFFER = GL_TEXTURE_BUFFER,
}; };
enum type_ : GLenum { enum type_ : GLenum {

View File

@@ -56,17 +56,17 @@ namespace fennec
namespace gl namespace gl
{ {
template<GLint FormatV, GLboolean ImmutableV> using texture1d = texture<TEX_1D, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture1d = texture<TEX_1D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture1dv = texture<TEX_1D_V, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture1d_array = texture<TEX_1D_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d = texture<TEX_2D, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture2d = texture<TEX_2D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2dv = texture<TEX_2D_V, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture2d_array = texture<TEX_2D_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture_rect = texture<TEX_RECT, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture_rect = texture<TEX_RECT, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms = texture<TEX_2D_MS, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms = texture<TEX_2D_MS, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture2dv_ms = texture<TEX_2D_MS_V, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture2d_ms_array = texture<TEX_2D_MS_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemap = texture<TEX_CUBEMAP, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using cubemap = texture<TEX_CUBEMAP, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using cubemapv = texture<TEX_CUBEMAP_V, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using cubemap_array = texture<TEX_CUBEMAP_ARRAY, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using texture3d = texture<TEX_3D, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using texture3d = texture<TEX_3D, FormatV, ImmutableV>;
template<GLint FormatV, GLboolean ImmutableV> using buffer_texture = texture<TEX_BUFFER, FormatV, ImmutableV>; template<GLint FormatV, GLboolean ImmutableV> using buffer_texture = texture<TEX_BUFFER, FormatV, ImmutableV>;
/// ///
/// \brief Wrapper for OpenGL Texture Objects /// \brief Wrapper for OpenGL Texture Objects
@@ -87,17 +87,17 @@ public:
static constexpr GLboolean immutable = ImmutableV; static constexpr GLboolean immutable = ImmutableV;
static constexpr GLboolean is_rect = type == TEX_RECT; static constexpr GLboolean is_rect = type == TEX_RECT;
static constexpr GLboolean is_buffered = type == TEX_BUFFER; static constexpr GLboolean is_buffered = type == TEX_BUFFER;
static constexpr GLboolean sampled = type == TEX_2D_MS or type == TEX_2D_MS_V; static constexpr GLboolean sampled = type == TEX_2D_MS or type == TEX_2D_MS_ARRAY;
static constexpr GLboolean cubemap = type == TEX_CUBEMAP or type == TEX_CUBEMAP_V; static constexpr GLboolean cubemap = type == TEX_CUBEMAP or type == TEX_CUBEMAP_ARRAY;
static constexpr GLboolean is_1d = type == TEX_1D or type == TEX_1D_V; static constexpr GLboolean is_1d = type == TEX_1D or type == TEX_1D_ARRAY;
static constexpr GLboolean is_2d = sampled or is_rect or type == TEX_2D or type == TEX_2D_V or cubemap; static constexpr GLboolean is_2d = sampled or is_rect or type == TEX_2D or type == TEX_2D_ARRAY or cubemap;
static constexpr GLboolean is_array = TypeV == TEX_1D_V or TypeV == TEX_2D_V or type == TEX_2D_MS_V or type == TEX_CUBEMAP_V; static constexpr GLboolean is_array = TypeV == TEX_1D_ARRAY or TypeV == TEX_2D_ARRAY or type == TEX_2D_MS_ARRAY or type == TEX_CUBEMAP_ARRAY;
static constexpr GLboolean is_3d = TypeV == TEX_3D; static constexpr GLboolean is_3d = TypeV == TEX_3D;
static constexpr GLboolean has_mipmaps = not(sampled or is_rect or is_buffered); static constexpr GLboolean has_mipmaps = not(sampled or is_rect or is_buffered);
static constexpr GLboolean use_1d = is_1d and not is_array; static constexpr GLboolean use_1d = is_1d and not is_array;
static constexpr GLboolean use_2d = (is_2d and not is_array) or (is_1d and is_array) and not sampled; static constexpr GLboolean use_2d = ((is_2d and not is_array) or (is_1d and is_array)) and not sampled;
static constexpr GLboolean use_3d = is_3d or (is_2d and is_array) and not sampled and not cubemap; static constexpr GLboolean use_3d = (is_3d or (is_2d and is_array)) and not (sampled or cubemap);
static constexpr GLint cubemap_faces = 6; static constexpr GLint cubemap_faces = 6;
static constexpr GLenum base_cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; static constexpr GLenum base_cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;

View File

@@ -23,7 +23,7 @@
#include <fennec/containers/map.h> #include <fennec/containers/map.h>
#include <fennec/containers/optional.h> #include <fennec/containers/optional.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h> #include <fennec/lang/typed.h>
namespace fennec namespace fennec
{ {

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# 2D Graphics (`gfx2d`) # 2D Graphics (`gfx2d`)
## Table of Contents ## Table of Contents
@@ -27,6 +29,11 @@ For the 2d rendering framework, Materials need to be rendered independently beca
no size constraints for images. This disallows us from using a meta-shader like in no size constraints for images. This disallows us from using a meta-shader like in
the 3d rendering framework. the 3d rendering framework.
I may have come up with a solution for the above problem. We can define software
subsections for images that are of differing size, then fit them to the optimal
texture array size. The textures will be centered in the storage, then have padding
that fits one of the wrapping models supported by samplers
```c++ ```c++
struct Object struct Object
{ {
@@ -62,3 +69,4 @@ struct Object
- Translucent objects will be sorted. We can cheat by using a z-index instead of a z-coordinate. - Translucent objects will be sorted. We can cheat by using a z-index instead of a z-coordinate.
This will allow us to sort objects as they are created. We can still bulk render each z-index, This will allow us to sort objects as they are created. We can still bulk render each z-index,
with meshes and objects being grouped by material. with meshes and objects being grouped by material.

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# 3D Graphics (`gfx3d`) # 3D Graphics (`gfx3d`)
## Table of Contents ## Table of Contents
@@ -67,8 +69,8 @@ Objects are identified with a manually provided type and ID. Object types includ
A user should never have to specify these and should be automatically generated by the respective components. A user should never have to specify these and should be automatically generated by the respective components.
Textures for 3D rendering are stored in various buffers with sizes of powers of 2. Ratios of `1:1` Textures for 3D rendering are stored in various buffers with sizes of powers of 2. Ratios of `1:1`
and `2:1` are allowed. The `2:1` ratio is specifically for spherical and cylindrical projection. UVs `2:1`, and `4:1` are allowed. The `2:1` ratio is specifically for spherical and cylindrical projection. UVs
may be transformed to use a `2:1` as if it were `1:2`. may be transformed to use a `2:1` as if it were `1:2`. Same applies for `4:1`
Cubemaps and 3D textures may only be `1:1`. Cubemaps and 3D textures may only be `1:1`.
- 8-Bit R Texture `4096, 2048, 1024, 512` (8) - 8-Bit R Texture `4096, 2048, 1024, 512` (8)
@@ -170,12 +172,12 @@ Debug View: Visibility Buffer
* S &rarr; used to represent the lighting model. * S &rarr; used to represent the lighting model.
* Diffuse &rarr; `RGBA8` * Diffuse &rarr; `RGBA8`
* A &rarr; Ambient Occlusion * A &rarr; Ambient Occlusion
* Specular &rarr; `RGB8`
* R &rarr; Roughness
* G &rarr; Specularity (sometimes called the Metallicity)
* B &rarr; Index of Refraction (IOR)
* Emission &rarr; `RGB8` * Emission &rarr; `RGB8`
* Normal &rarr; `RGB8` * Normal &rarr; `RGB8`
* Specular &rarr; `RGB8`
* R &rarr; Roughness
* G &rarr; Specularity (sometimes called the Metallicness)
* B &rarr; Index of Refraction (IOR)
Debug View: Depth, Stencil, Diffuse, Emission, Normal, Specularity Debug View: Depth, Stencil, Diffuse, Emission, Normal, Specularity
@@ -195,9 +197,9 @@ We can combine all of these into one framebuffer:
- Depth - Stencil &rarr; `D24_S8` - Depth - Stencil &rarr; `D24_S8`
- Visibility Info &rarr; `RGB32I` - Visibility Info &rarr; `RGB32I`
- Diffuse &rarr; `RGBA8` - Diffuse &rarr; `RGBA8`
- Specular &rarr; `RGB8`
- Emission &rarr; `RGB8` - Emission &rarr; `RGB8`
- Normal &rarr; `RGB8` - Normal &rarr; `RGB8`
- Specular &rarr; `RGB8`
- Lighting Buffer &rarr; `RGB16` w/ Mipmapping - Lighting Buffer &rarr; `RGB16` w/ Mipmapping
- One more slot left open for another - One more slot left open for another

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# 3D Physics (`physics3d`) # 3D Physics (`physics3d`)
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Artifical Intelligence (`ai`) # Artifical Intelligence (`ai`)
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Containers Library (`containers`) # Containers Library (`containers`)
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Planning Documentation for fennec # Planning Documentation for fennec
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# C++ Language Library (`lang`) # C++ Language Library (`lang`)
## Table of Contents ## Table of Contents

BIN
planning/ControlScene.ods Normal file

Binary file not shown.

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# fennec # fennec
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Language Processing Library (`langproc`) # Language Processing Library (`langproc`)
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Memory Library (`memory`) # Memory Library (`memory`)
## Table of Contents ## Table of Contents

View File

@@ -1,4 +1,6 @@
<!-- I release these notes into the public domain -->
# Platform Support Library (`platform`) # Platform Support Library (`platform`)
## Table of Contents ## Table of Contents
@@ -67,3 +69,56 @@ then support for other platforms will be resumed.
with the principles of this engine. fennec will avoid using proprietary libraries except with the principles of this engine. fennec will avoid using proprietary libraries except
when strictly necessary, such as support for Windows and MacOS. fennec will interact when strictly necessary, such as support for Windows and MacOS. fennec will interact
with any drivers required for the listed operating systems above, even if proprietary. with any drivers required for the listed operating systems above, even if proprietary.
## Notes
We want this system to be fairly modular, renderers and their respective
gfxcontext implementation should be a drop-in, as well as window implementation.
This is a fairly complex problem to solve, especially since most display protocols
have their own specific implementation for supporting different contexts.
To illustrate this problem, let's say we have SDL and OpenGL implemented.
If we were to add Vulkan, there are Vulkan specific functions
for creating a window compatible with SDL, i.e. SDL_Vulkan_CreateSurface.
Who should know how to implement this function? How do we define the API
so that we do not have to modify existing classes to add Vulkan support?
The easiest solution to this problem is template functions. We can have a
template that takes a Renderer type as a template parameter, then initialize
the window for that. Now, if someone wants to create a Vulkan renderer, all they
have to do is write an overload for the template function. This can be neatly
wrapped up in a single C++ file. Only the gfxcontext implementation has to know
of this function's existence since it will be the one calling the function.
The main drawback with this implementation is an outside observer calling the
template function directly. Only the one C++ file knows of its existence. Template
functions are inlined after all. There are two options to solve this, the ``[[noinline]]``
attribute, or we simply scope protect the function and create it purely from a
"driver" standpoint. We can register drivers with the platform, then retrieve a
list of drivers with a specific type, e.g. glcontext, then the type aware implementation
is isolated to the C++ file associated with glcontext, and glcontext registers
itself with the platform. We can give drivers a priority so that Vulkan, a more
modern and "more powerful" renderer is chosen first, if available, and falls back
to OpenGL.
Now we run into the issue of, what if we want to implement Vulkan and Wayland separately?
These implementations will be part of the core engine, but let's take a more contrived
example; X-Box and Playstation. X-Box and Playstation have their own protocols for
display rendering, but both use DirectX. Say someone implements a DirectX api for Desktop
computers, then someone else implements a windowing system for X-Box or Playstation.
If another user wants to use DirectX with X-Box/Playstation, they will have to write
their own overloads for that implementation.
The only viable solution for this problem is to rely on the Open Source community.
Pray that someone finds both engine extensions and writes the overloads for you.
This might sound very familiar to modders, and this is my intention with this engine.
Pieces should be modular, and should be easily connected when two non-dependent systems
have underlying interdependencies.
There is one more option that I have come up with; mapping type ids. The implementation
of typed.h generates type ids *at runtime* which allows us to map a pair of ids for this
purpose. We can use a pair of window and gfxcontext uuids to determine the loading functions.
All we would need to do is register a function that takes a window as an arguments and
constructs the gfxcontext. We can combine this with the above to allow scoped access to
the classes if that is needed.

26
planning/RENDERERS.md Normal file
View File

@@ -0,0 +1,26 @@
<!-- I release these notes into the public domain -->
# Renderers (`renderers`)
## Introduction
&ensp; This library contains headers and classes related to creating renderers
that wrap various graphics pipelines, e.g. OpenGL & Vulkan.
## Implementation
OpenGL will be implemented first for prototyping, then Vulkan will
be implemented. These will be the first two renderers with official
support. OpenGL will be implemented twice, one targeting modern features,
and a fallback targeting OpenGL 4.3 / GLES 3.2.
OpenGL will be wrapped in a manner that reflects the Vulkan API. This
will help achieve higher performance with driver usage in OpenGL, and
it will make building pipelines on top of OpenGL easier. This will also
give the advantage of a cleaner porting process when writing the Vulkan
pipeline.

View File

@@ -41,9 +41,8 @@ void platform::initialize() {
void platform::shutdown() { void platform::shutdown() {
} }
platform::global_context& platform::_get_globals() { window* platform::create_window(const window::config& config) {
static global_context ctx;
return ctx;
} }
} }