- 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:
@@ -21,18 +21,6 @@ cmake_minimum_required(VERSION 3.30)
|
||||
project(fennec)
|
||||
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)
|
||||
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
|
||||
endmacro()
|
||||
@@ -45,10 +33,26 @@ macro(fennec_add_link_libraries)
|
||||
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(fennec_add_shared_libraries)
|
||||
list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN})
|
||||
endmacro()
|
||||
|
||||
macro(fennec_add_link_options)
|
||||
list(APPEND FENNEC_PRIVATE_LINK_OPTIONS ${ARGN})
|
||||
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("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
|
||||
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
|
||||
@@ -90,6 +94,13 @@ add_library(fennec STATIC
|
||||
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 ===========================================================================================================
|
||||
include/fennec/containers/containers.h
|
||||
|
||||
@@ -130,7 +141,7 @@ add_library(fennec STATIC
|
||||
include/fennec/lang/type_sequences.h
|
||||
include/fennec/lang/type_traits.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/utility.h
|
||||
include/fennec/lang/integer.h
|
||||
@@ -218,13 +229,13 @@ add_library(fennec STATIC
|
||||
|
||||
include/fennec/platform/interface/fwd.h
|
||||
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
|
||||
include/fennec/platform/interface/window.h
|
||||
|
||||
|
||||
# EXTRA SOURCES ========================================================================================================
|
||||
# EXTRA SOURCES ========================================================================================================
|
||||
|
||||
${FENNEC_EXTRA_SOURCES}
|
||||
include/fennec/platform/interface/window.h
|
||||
include/fennec/platform/sdl/sdlwindow.h
|
||||
include/fennec/containers/bintree.h
|
||||
)
|
||||
|
||||
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
|
||||
${FENNEC_LINK_LIBRARIES}
|
||||
${FENNEC_SHARED_LIBRARIES}
|
||||
|
||||
cpptrace::cpptrace
|
||||
SDL3::SDL3-shared
|
||||
)
|
||||
|
||||
add_custom_command(TARGET fennec POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:SDL3::SDL3-shared> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
|
||||
)
|
||||
foreach (_LIB IN ITEMS ${FENNEC_SHARED_LIBRARIES})
|
||||
add_custom_command(TARGET fennec POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_LINKER_FILE:${_LIB}> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
|
||||
)
|
||||
endforeach ()
|
||||
|
||||
|
||||
# DOXYGEN ==============================================================================================================
|
||||
|
||||
@@ -18,4 +18,13 @@
|
||||
|
||||
set(SDL_AUDIO 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
|
||||
)
|
||||
|
||||
|
||||
299
include/fennec/containers/bintree.h
Normal file
299
include/fennec/containers/bintree.h
Normal 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
|
||||
@@ -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
|
||||
@@ -294,9 +294,35 @@ public:
|
||||
/// \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
|
||||
/// \val The optional to move
|
||||
/// \param args The arguments to construct with
|
||||
template<typename...ArgsT>
|
||||
constexpr T& emplace(ArgsT&&...args) {
|
||||
if (_set) {
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
protected:
|
||||
struct node {
|
||||
optional<TypeT> value;
|
||||
optional<value_t> value;
|
||||
size_t parent, child, prev, next;
|
||||
size_t depth, num_children;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define FENNEC_CORE_EVENT_H
|
||||
|
||||
#include <fennec/lang/types.h>
|
||||
#include <fennec/lang/typeuuid.h>
|
||||
#include <fennec/lang/typed.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
@@ -22,8 +22,9 @@
|
||||
#include <fennec/containers/list.h>
|
||||
#include <fennec/langproc/strings/cstring.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/window.h>
|
||||
|
||||
/*
|
||||
* 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 symbol = void*;
|
||||
|
||||
template<typename ctor>
|
||||
struct driver {
|
||||
int priority;
|
||||
ctor constructor;
|
||||
};
|
||||
|
||||
const string name;
|
||||
|
||||
virtual ~platform() = default;
|
||||
@@ -76,14 +83,21 @@ public:
|
||||
virtual void initialize(); // Initialize 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:
|
||||
template<typename PlatformT>
|
||||
explicit platform(const cstring& name, PlatformT* type)
|
||||
: typed(type)
|
||||
, name(name) {
|
||||
auto& globals = _get_globals();
|
||||
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
|
||||
globals.singleton = this;
|
||||
assertf(singleton == nullptr, "Conflicting platform implementations!");
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -92,31 +106,12 @@ private:
|
||||
// Static Stuff ========================================================================================================
|
||||
|
||||
public:
|
||||
template<typename ctor>
|
||||
struct driver {
|
||||
int priority;
|
||||
ctor constructor;
|
||||
};
|
||||
|
||||
struct global_context {
|
||||
platform* singleton;
|
||||
|
||||
global_context()
|
||||
: singleton(nullptr) {
|
||||
static platform* instance() {
|
||||
return singleton;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static global_context& _get_globals();
|
||||
|
||||
public:
|
||||
static const global_context& get_globals() {
|
||||
return _get_globals();
|
||||
}
|
||||
|
||||
static platform* instance() {
|
||||
return _get_globals().singleton;
|
||||
}
|
||||
static platform* singleton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H
|
||||
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H
|
||||
|
||||
#include <fennec/lang/types.h>
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
|
||||
@@ -38,6 +39,8 @@ namespace fennec
|
||||
|
||||
class window {
|
||||
public:
|
||||
virtual ~window() = default;
|
||||
|
||||
enum flags : uint8_t {
|
||||
fullscreen = 0x1 << 0,
|
||||
borderless = 0x1 << 1,
|
||||
@@ -49,8 +52,8 @@ public:
|
||||
};
|
||||
|
||||
enum vsync {
|
||||
off = 0,
|
||||
vsync = 1,
|
||||
vsync_off = 0,
|
||||
vsync_on = 1,
|
||||
adaptive_sync = -1,
|
||||
};
|
||||
|
||||
@@ -74,6 +77,8 @@ public:
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
virtual bool running() = 0;
|
||||
|
||||
bool is_fullscreen() const {
|
||||
return _config.flags & fullscreen;
|
||||
}
|
||||
@@ -115,8 +120,14 @@ public:
|
||||
virtual void grab_mouse(bool) = 0;
|
||||
virtual void grab_keyboard(bool) = 0;
|
||||
virtual void set_title(const cstring&) = 0;
|
||||
virtual void set_title(const string& str) = 0;
|
||||
virtual void set_vsync_mode(int8_t) = 0;
|
||||
virtual void set_title(const string&) = 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:
|
||||
window* _parent;
|
||||
|
||||
@@ -31,11 +31,19 @@
|
||||
#ifndef FENNEC_PLATFORM_SDL_SDLWINDOW_H
|
||||
#define FENNEC_PLATFORM_SDL_SDLWINDOW_H
|
||||
|
||||
#include <fennec/platform/interface/window.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
class sdlwindow : public window {
|
||||
public:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_PLATFORM_SDL_SDLWINDOW_H
|
||||
45
include/fennec/renderers/interface/forward.h
Normal file
45
include/fennec/renderers/interface/forward.h
Normal 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
|
||||
58
include/fennec/renderers/interface/gfxcontext.h
Normal file
58
include/fennec/renderers/interface/gfxcontext.h
Normal 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
|
||||
41
include/fennec/renderers/interface/gfxsubpass.h
Normal file
41
include/fennec/renderers/interface/gfxsubpass.h
Normal 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
|
||||
80
include/fennec/renderers/interface/renderer.h
Normal file
80
include/fennec/renderers/interface/renderer.h
Normal 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
|
||||
@@ -61,16 +61,16 @@ enum access_ : GLbitfield {
|
||||
|
||||
enum texture_ : GLenum {
|
||||
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_V = GL_TEXTURE_2D_ARRAY,
|
||||
TEX_2D_ARRAY = GL_TEXTURE_2D_ARRAY,
|
||||
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_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,
|
||||
|
||||
@@ -57,14 +57,14 @@ namespace gl
|
||||
{
|
||||
|
||||
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 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 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 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 buffer_texture = texture<TEX_BUFFER, FormatV, ImmutableV>;
|
||||
|
||||
@@ -87,17 +87,17 @@ public:
|
||||
static constexpr GLboolean immutable = ImmutableV;
|
||||
static constexpr GLboolean is_rect = type == TEX_RECT;
|
||||
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 cubemap = type == TEX_CUBEMAP or type == TEX_CUBEMAP_V;
|
||||
static constexpr GLboolean is_1d = type == TEX_1D or type == TEX_1D_V;
|
||||
static constexpr GLboolean is_2d = sampled or is_rect or type == TEX_2D or type == TEX_2D_V 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 sampled = type == TEX_2D_MS or type == TEX_2D_MS_ARRAY;
|
||||
static constexpr GLboolean cubemap = type == TEX_CUBEMAP or type == TEX_CUBEMAP_ARRAY;
|
||||
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_ARRAY or cubemap;
|
||||
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 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_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_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 or cubemap);
|
||||
|
||||
static constexpr GLint cubemap_faces = 6;
|
||||
static constexpr GLenum base_cubemap_face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <fennec/containers/map.h>
|
||||
#include <fennec/containers/optional.h>
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
#include <fennec/lang/typeuuid.h>
|
||||
#include <fennec/lang/typed.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# 2D Graphics (`gfx2d`)
|
||||
|
||||
## 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
|
||||
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++
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# 3D Graphics (`gfx3d`)
|
||||
|
||||
## 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.
|
||||
|
||||
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
|
||||
may be transformed to use a `2:1` as if it were `1:2`.
|
||||
`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`. Same applies for `4:1`
|
||||
Cubemaps and 3D textures may only be `1:1`.
|
||||
|
||||
- 8-Bit R Texture `4096, 2048, 1024, 512` (8)
|
||||
@@ -170,12 +172,12 @@ Debug View: Visibility Buffer
|
||||
* S → used to represent the lighting model.
|
||||
* Diffuse → `RGBA8`
|
||||
* A → Ambient Occlusion
|
||||
* Emission → `RGB8`
|
||||
* Normal → `RGB8`
|
||||
* Specular → `RGB8`
|
||||
* R → Roughness
|
||||
* G → Specularity (sometimes called the Metallicness)
|
||||
* G → Specularity (sometimes called the Metallicity)
|
||||
* B → Index of Refraction (IOR)
|
||||
* Emission → `RGB8`
|
||||
* Normal → `RGB8`
|
||||
|
||||
Debug View: Depth, Stencil, Diffuse, Emission, Normal, Specularity
|
||||
|
||||
@@ -195,9 +197,9 @@ We can combine all of these into one framebuffer:
|
||||
- Depth - Stencil → `D24_S8`
|
||||
- Visibility Info → `RGB32I`
|
||||
- Diffuse → `RGBA8`
|
||||
- Specular → `RGB8`
|
||||
- Emission → `RGB8`
|
||||
- Normal → `RGB8`
|
||||
- Specular → `RGB8`
|
||||
- Lighting Buffer → `RGB16` w/ Mipmapping
|
||||
- One more slot left open for another
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# 3D Physics (`physics3d`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Artifical Intelligence (`ai`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Containers Library (`containers`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Planning Documentation for fennec
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# C++ Language Library (`lang`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
BIN
planning/ControlScene.ods
Normal file
BIN
planning/ControlScene.ods
Normal file
Binary file not shown.
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# fennec
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Language Processing Library (`langproc`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Memory Library (`memory`)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Platform Support Library (`platform`)
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
||||
## 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
26
planning/RENDERERS.md
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
<!-- I release these notes into the public domain -->
|
||||
|
||||
# Renderers (`renderers`)
|
||||
|
||||
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
  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.
|
||||
@@ -41,9 +41,8 @@ void platform::initialize() {
|
||||
void platform::shutdown() {
|
||||
}
|
||||
|
||||
platform::global_context& platform::_get_globals() {
|
||||
static global_context ctx;
|
||||
return ctx;
|
||||
window* platform::create_window(const window::config& config) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user