diff --git a/CMakeLists.txt b/CMakeLists.txt index 5038094..a6ce057 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 $ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} -) +foreach (_LIB IN ITEMS ${FENNEC_SHARED_LIBRARIES}) + add_custom_command(TARGET fennec POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + ) +endforeach () # DOXYGEN ============================================================================================================== diff --git a/cmake/sdl.cmake b/cmake/sdl.cmake index 7327201..8978848 100644 --- a/cmake/sdl.cmake +++ b/cmake/sdl.cmake @@ -18,4 +18,13 @@ set(SDL_AUDIO OFF) set(SDL_RENDER OFF) -add_subdirectory(external/SDL) \ No newline at end of file +add_subdirectory(${FENNEC_SOURCE_DIR}/external/SDL) + +fennec_add_sources( + include/fennec/platform/sdl/sdlwindow.h +) + +fennec_add_shared_libraries( + SDL3::SDL3-shared +) + diff --git a/include/fennec/containers/bintree.h b/include/fennec/containers/bintree.h new file mode 100644 index 0000000..029365b --- /dev/null +++ b/include/fennec/containers/bintree.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 +#include +#include +#include +#include + +namespace fennec +{ + +template +struct bintree { + + // Definitions ========================================================================================================= +protected: + struct node; + +public: + using value_t = TypeT; + using alloc_t = allocator_traits::template rebind; + static constexpr size_t root = 0; + static constexpr size_t npos = -1; + +protected: + struct node { + optional value; + size_t parent, left, right; + size_t depth; + + constexpr node() + : value(nullopt) + , parent(npos), left(npos), right(npos) + , depth(0) { + } + + template + constexpr node(size_t p, size_t l, size_t r, size_t d, ArgsT&&...args) + : value(fennec::forward(args)...) + , parent(p), left(l), right(r) + , depth(d) { + } + + constexpr ~node() { + parent = npos; + left = npos; + right = npos; + depth = npos; + } + }; + + using table_t = allocation; + using freed_t = list; + +// 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(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 + constexpr size_t emplace_left(size_t p, ArgsT&&...args) { + return this->_insert_left(p, fennec::forward(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 + 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(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 + 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(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 \ No newline at end of file diff --git a/include/fennec/containers/multiset.h b/include/fennec/containers/multiset.h deleted file mode 100644 index ed79ca3..0000000 --- a/include/fennec/containers/multiset.h +++ /dev/null @@ -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 . -// ===================================================================================================================== - -/// -/// \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 -#include -#include -#include -#include -#include - -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, class Equals = equality, class Alloc = allocator> -struct multiset { - -// Definitions ========================================================================================================= -public: - using alloc_t = typename allocator_traits::template rebind; - 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 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(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 - constexpr void emplace(ArgsT&&...args) { - this->_insert(fennec::forward(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 - constexpr void _insert(ArgsT&&...args) { - if (_size == 0 or static_cast(_size) / capacity() >= _load) { // expand when full - _expand(); - } - - elem_t value(fennec::forward(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 _alloc; - hash_t _hash; - equal_t _equal; - size_t _size; - size_t _sumpsl; - float _load; -}; - -} - -#endif // FENNEC_CONTAINERS_SET_H diff --git a/include/fennec/containers/optional.h b/include/fennec/containers/optional.h index a24546a..006acfd 100644 --- a/include/fennec/containers/optional.h +++ b/include/fennec/containers/optional.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(val); + } else { + fennec::construct(&_val, fennec::forward(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 constexpr T& emplace(ArgsT&&...args) { if (_set) { diff --git a/include/fennec/containers/rdtree.h b/include/fennec/containers/rdtree.h index 6b0ec59..80c87e0 100644 --- a/include/fennec/containers/rdtree.h +++ b/include/fennec/containers/rdtree.h @@ -58,7 +58,7 @@ public: protected: struct node { - optional value; + optional value; size_t parent, child, prev, next; size_t depth, num_children; diff --git a/include/fennec/core/event.h b/include/fennec/core/event.h index 4ccd1a0..070cd25 100644 --- a/include/fennec/core/event.h +++ b/include/fennec/core/event.h @@ -20,7 +20,7 @@ #define FENNEC_CORE_EVENT_H #include -#include +#include namespace fennec { diff --git a/include/fennec/lang/typeuuid.h b/include/fennec/lang/typed.h similarity index 100% rename from include/fennec/lang/typeuuid.h rename to include/fennec/lang/typed.h diff --git a/include/fennec/platform/interface/platform.h b/include/fennec/platform/interface/platform.h index 3a2f52f..79d2e45 100644 --- a/include/fennec/platform/interface/platform.h +++ b/include/fennec/platform/interface/platform.h @@ -22,8 +22,9 @@ #include #include #include -#include +#include #include +#include /* * 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 + 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* create_window(const window::config& config); + static void register_window_driver(window_driver&& driver); + protected: template 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 - 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; }; } diff --git a/include/fennec/platform/interface/window.h b/include/fennec/platform/interface/window.h index 21a7783..54ef937 100644 --- a/include/fennec/platform/interface/window.h +++ b/include/fennec/platform/interface/window.h @@ -30,6 +30,7 @@ #ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H #define FENNEC_PLATFORM_INTERFACE_WINDOW_H + #include #include @@ -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; } @@ -110,13 +115,19 @@ public: // Modifiers =========================================================================================================== - virtual void set_fullscreen(bool) = 0; - virtual void set_borderless(bool) = 0; - 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_fullscreen(bool) = 0; + virtual void set_borderless(bool) = 0; + 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&) = 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; diff --git a/include/fennec/platform/sdl/sdlwindow.h b/include/fennec/platform/sdl/sdlwindow.h index ebd9f56..603e2fb 100644 --- a/include/fennec/platform/sdl/sdlwindow.h +++ b/include/fennec/platform/sdl/sdlwindow.h @@ -31,11 +31,19 @@ #ifndef FENNEC_PLATFORM_SDL_SDLWINDOW_H #define FENNEC_PLATFORM_SDL_SDLWINDOW_H +#include + namespace fennec { +class sdlwindow : public window { +public: +private: + +}; + } #endif // FENNEC_PLATFORM_SDL_SDLWINDOW_H \ No newline at end of file diff --git a/include/fennec/renderers/interface/forward.h b/include/fennec/renderers/interface/forward.h new file mode 100644 index 0000000..121bbfe --- /dev/null +++ b/include/fennec/renderers/interface/forward.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 \ No newline at end of file diff --git a/include/fennec/renderers/interface/gfxcontext.h b/include/fennec/renderers/interface/gfxcontext.h new file mode 100644 index 0000000..5573e3a --- /dev/null +++ b/include/fennec/renderers/interface/gfxcontext.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 + +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 \ No newline at end of file diff --git a/include/fennec/renderers/interface/gfxsubpass.h b/include/fennec/renderers/interface/gfxsubpass.h new file mode 100644 index 0000000..4ddc67c --- /dev/null +++ b/include/fennec/renderers/interface/gfxsubpass.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 \ No newline at end of file diff --git a/include/fennec/renderers/interface/renderer.h b/include/fennec/renderers/interface/renderer.h new file mode 100644 index 0000000..ce1ee00 --- /dev/null +++ b/include/fennec/renderers/interface/renderer.h @@ -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 . +// ===================================================================================================================== + +/// +/// \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 +#include +#include + +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 \ No newline at end of file diff --git a/include/fennec/platform/opengl/lib/buffer.h b/include/fennec/renderers/opengl/lib/buffer.h similarity index 100% rename from include/fennec/platform/opengl/lib/buffer.h rename to include/fennec/renderers/opengl/lib/buffer.h diff --git a/include/fennec/platform/opengl/lib/enum.h b/include/fennec/renderers/opengl/lib/enum.h similarity index 95% rename from include/fennec/platform/opengl/lib/enum.h rename to include/fennec/renderers/opengl/lib/enum.h index a9c61f3..a8383f8 100644 --- a/include/fennec/platform/opengl/lib/enum.h +++ b/include/fennec/renderers/opengl/lib/enum.h @@ -60,21 +60,21 @@ enum access_ : GLbitfield { }; enum texture_ : GLenum { - TEX_1D = GL_TEXTURE_1D, - TEX_1D_V = GL_TEXTURE_1D_ARRAY, + TEX_1D = GL_TEXTURE_1D, + TEX_1D_ARRAY = GL_TEXTURE_1D_ARRAY, - TEX_2D = GL_TEXTURE_2D, - TEX_2D_V = GL_TEXTURE_2D_ARRAY, - TEX_2D_MS = GL_TEXTURE_2D_MULTISAMPLE, - TEX_2D_MS_V = GL_TEXTURE_2D_MULTISAMPLE_ARRAY, - TEX_RECT = GL_TEXTURE_RECTANGLE, + TEX_2D = GL_TEXTURE_2D, + TEX_2D_ARRAY = GL_TEXTURE_2D_ARRAY, + TEX_2D_MS = GL_TEXTURE_2D_MULTISAMPLE, + 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 = GL_TEXTURE_CUBE_MAP, + TEX_CUBEMAP_ARRAY = GL_TEXTURE_CUBE_MAP_ARRAY, TEX_3D = GL_TEXTURE_3D, - TEX_BUFFER = GL_TEXTURE_BUFFER, + TEX_BUFFER = GL_TEXTURE_BUFFER, }; enum type_ : GLenum { diff --git a/include/fennec/platform/opengl/lib/fwd.h b/include/fennec/renderers/opengl/lib/fwd.h similarity index 100% rename from include/fennec/platform/opengl/lib/fwd.h rename to include/fennec/renderers/opengl/lib/fwd.h diff --git a/include/fennec/platform/opengl/lib/texture.h b/include/fennec/renderers/opengl/lib/texture.h similarity index 87% rename from include/fennec/platform/opengl/lib/texture.h rename to include/fennec/renderers/opengl/lib/texture.h index 5e8d59c..f13acbe 100644 --- a/include/fennec/platform/opengl/lib/texture.h +++ b/include/fennec/renderers/opengl/lib/texture.h @@ -56,17 +56,17 @@ namespace fennec namespace gl { -template using texture1d = texture; -template using texture1dv = texture; -template using texture2d = texture; -template using texture2dv = texture; -template using texture_rect = texture; -template using texture2d_ms = texture; -template using texture2dv_ms = texture; -template using cubemap = texture; -template using cubemapv = texture; -template using texture3d = texture; -template using buffer_texture = texture; +template using texture1d = texture; +template using texture1d_array = texture; +template using texture2d = texture; +template using texture2d_array = texture; +template using texture_rect = texture; +template using texture2d_ms = texture; +template using texture2d_ms_array = texture; +template using cubemap = texture; +template using cubemap_array = texture; +template using texture3d = texture; +template using buffer_texture = texture; /// /// \brief Wrapper for OpenGL Texture Objects @@ -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; diff --git a/include/fennec/platform/opengl/lib/vertex_array.h b/include/fennec/renderers/opengl/lib/vertex_array.h similarity index 100% rename from include/fennec/platform/opengl/lib/vertex_array.h rename to include/fennec/renderers/opengl/lib/vertex_array.h diff --git a/include/fennec/scene/component.h b/include/fennec/scene/component.h index f33d658..1b7d2d9 100644 --- a/include/fennec/scene/component.h +++ b/include/fennec/scene/component.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace fennec { diff --git a/planning/2D_GRAPHICS.md b/planning/2D_GRAPHICS.md index 4886923..98ae1fe 100644 --- a/planning/2D_GRAPHICS.md +++ b/planning/2D_GRAPHICS.md @@ -1,4 +1,6 @@ + + # 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 { @@ -61,4 +68,5 @@ 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. \ No newline at end of file + with meshes and objects being grouped by material. + diff --git a/planning/3D_GRAPHICS.md b/planning/3D_GRAPHICS.md index 1fdafb5..71e817d 100644 --- a/planning/3D_GRAPHICS.md +++ b/planning/3D_GRAPHICS.md @@ -1,4 +1,6 @@ + + # 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 + * Specular → `RGB8` + * R → Roughness + * G → Specularity (sometimes called the Metallicity) + * B → Index of Refraction (IOR) * Emission → `RGB8` * Normal → `RGB8` - * Specular → `RGB8` - * R → Roughness - * G → Specularity (sometimes called the Metallicness) - * B → Index of Refraction (IOR) 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 diff --git a/planning/3D_PHYSICS.md b/planning/3D_PHYSICS.md index 1661d36..24c55ed 100644 --- a/planning/3D_PHYSICS.md +++ b/planning/3D_PHYSICS.md @@ -1,4 +1,6 @@ + + # 3D Physics (`physics3d`) ## Table of Contents diff --git a/planning/ARTIFICIAL_INTELLIGENCE.md b/planning/ARTIFICIAL_INTELLIGENCE.md index 5e2181e..7004f35 100644 --- a/planning/ARTIFICIAL_INTELLIGENCE.md +++ b/planning/ARTIFICIAL_INTELLIGENCE.md @@ -1,4 +1,6 @@ + + # Artifical Intelligence (`ai`) ## Table of Contents diff --git a/planning/CONTAINERS.md b/planning/CONTAINERS.md index 91d1ed4..424d808 100644 --- a/planning/CONTAINERS.md +++ b/planning/CONTAINERS.md @@ -1,4 +1,6 @@ + + # Containers Library (`containers`) ## Table of Contents diff --git a/planning/CONTENTS.md b/planning/CONTENTS.md index 40f8369..594b2fc 100644 --- a/planning/CONTENTS.md +++ b/planning/CONTENTS.md @@ -1,4 +1,6 @@ + + # Planning Documentation for fennec ## Table of Contents diff --git a/planning/CPP_LANGUAGE.md b/planning/CPP_LANGUAGE.md index eee50a9..8e8a092 100644 --- a/planning/CPP_LANGUAGE.md +++ b/planning/CPP_LANGUAGE.md @@ -1,4 +1,6 @@ + + # C++ Language Library (`lang`) ## Table of Contents diff --git a/planning/ControlScene.ods b/planning/ControlScene.ods new file mode 100644 index 0000000..738d158 Binary files /dev/null and b/planning/ControlScene.ods differ diff --git a/planning/ENGINE.md b/planning/ENGINE.md index 28ec621..e720d89 100644 --- a/planning/ENGINE.md +++ b/planning/ENGINE.md @@ -1,4 +1,6 @@ + + # fennec ## Table of Contents diff --git a/planning/LANGUAGE_PROCESSING.md b/planning/LANGUAGE_PROCESSING.md index 8ba8bc4..69b94b7 100644 --- a/planning/LANGUAGE_PROCESSING.md +++ b/planning/LANGUAGE_PROCESSING.md @@ -1,4 +1,6 @@ + + # Language Processing Library (`langproc`) ## Table of Contents diff --git a/planning/MEMORY.md b/planning/MEMORY.md index 729cdfe..f1ef033 100644 --- a/planning/MEMORY.md +++ b/planning/MEMORY.md @@ -1,4 +1,6 @@ + + # Memory Library (`memory`) ## Table of Contents diff --git a/planning/PLATFORM_SUPPORT.md b/planning/PLATFORM_SUPPORT.md index 860bfae..07755e0 100644 --- a/planning/PLATFORM_SUPPORT.md +++ b/planning/PLATFORM_SUPPORT.md @@ -1,4 +1,6 @@ + + # 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. diff --git a/planning/RENDERERS.md b/planning/RENDERERS.md new file mode 100644 index 0000000..8dc0f8d --- /dev/null +++ b/planning/RENDERERS.md @@ -0,0 +1,26 @@ + + + +# 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. diff --git a/source/platform/interface/platform.cpp b/source/platform/interface/platform.cpp index dbe2e54..ce5d967 100644 --- a/source/platform/interface/platform.cpp +++ b/source/platform/interface/platform.cpp @@ -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) { + } } \ No newline at end of file