Compare commits

...

10 Commits

Author SHA1 Message Date
8867576a2e Delete doxy/Doxyfile 2025-09-17 21:17:52 +00:00
788f63d092 - Added generated Doxyfile to .gitignore 2025-09-17 17:16:47 -04:00
a35f2a699d - Fixed some missing and erroneous testing logic for containers
- Lots of bug-fixing for containers
 - Performance optimization for containers
2025-09-17 17:13:52 -04:00
80925965d4 - GCC ARM64 Support, i.e. natively compiled with gcc on arm64 2025-09-15 02:35:34 +00:00
f2a45aa913 - Began outlining tokenizer.h and priority_queue.h
- Began outlining sdl implementation
- Added some helper definitions to various classes
- Added contains to string.h and wstring.h
2025-09-13 20:33:53 -04:00
3565bbbc52 - Fixed some logic errors with assertions for wide vs. byte files.
- Changed getline and getwline to use gets instead of the experimental functions. These, in theory, will be slightly faster.
2025-09-11 16:58:32 -04:00
375492ef7b - "Finished" sequence.h, there's more to do, but the basic functionality is there
- bintree.h is implemented according to the needs of sequence.h at present
2025-08-31 14:38:05 -04:00
dbcb50349d - Binary Tree (Partial)
- Sequence (Partial)
2025-08-30 22:11:41 -04:00
992a02db3e - 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)
2025-08-28 00:01:54 -04:00
e1eaf97961 - Switched to SDL for main branch, will revisit custom implementation later. 2025-08-23 20:09:53 -04:00
98 changed files with 3074 additions and 19758 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@
/bin/ /bin/
/lib/ /lib/
/doxy/README.md /doxy/README.md
/doxy/Doxyfile

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "external/cpptrace"] [submodule "external/cpptrace"]
path = external/cpptrace path = external/cpptrace
url = https://github.com/jeremy-rifkin/cpptrace.git url = https://github.com/jeremy-rifkin/cpptrace.git
[submodule "external/SDL"]
path = external/SDL
url = https://github.com/libsdl-org/SDL

View File

@@ -16,21 +16,11 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# ====================================================================================================================== # ======================================================================================================================
cmake_minimum_required(VERSION 3.30) cmake_minimum_required(VERSION 3.28)
project(fennec) project(fennec)
# External dependencies should be loaded here
add_subdirectory(external/cpptrace)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_C_STANDARD 23)
set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(FENNEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(fennec-dependencies
COMMAND ${CMAKE_COMMAND} -E echo "Running dependencies."
COMMENT "Running dependencies."
)
macro(fennec_add_sources) macro(fennec_add_sources)
list(APPEND FENNEC_EXTRA_SOURCES ${ARGN}) list(APPEND FENNEC_EXTRA_SOURCES ${ARGN})
endmacro() endmacro()
@@ -43,6 +33,26 @@ macro(fennec_add_link_libraries)
list(APPEND FENNEC_LINK_LIBRARIES ${ARGN}) list(APPEND FENNEC_LINK_LIBRARIES ${ARGN})
endmacro() endmacro()
macro(fennec_add_shared_libraries)
list(APPEND FENNEC_SHARED_LIBRARIES ${ARGN})
endmacro()
macro(fennec_add_link_options)
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 scripts
include("${FENNEC_SOURCE_DIR}/cmake/version.cmake") include("${FENNEC_SOURCE_DIR}/cmake/version.cmake")
include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake") include("${FENNEC_SOURCE_DIR}/cmake/platform.cmake")
@@ -62,7 +72,7 @@ include_directories(${FENNEC_SOURCE_DIR}/include)
# Metaprogramming is a dependency for generating various type info before compilation of the engine. # Metaprogramming is a dependency for generating various type info before compilation of the engine.
add_subdirectory(metaprogramming) add_subdirectory(metaprogramming)
# Specify where to send libraries and executables
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/lib/${FENNEC_BUILD_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${FENNEC_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME})
@@ -84,10 +94,18 @@ add_library(fennec STATIC
include/fennec/scene/component.h include/fennec/scene/component.h
# Renderers ============================================================================================================
include/fennec/renderers/interface/forward.h
include/fennec/renderers/interface/gfxcontext.h
include/fennec/renderers/interface/gfxsubpass.h
# CONTAINERS =========================================================================================================== # CONTAINERS ===========================================================================================================
include/fennec/containers/containers.h include/fennec/containers/containers.h
include/fennec/containers/array.h include/fennec/containers/array.h
include/fennec/containers/bintree.h
include/fennec/containers/deque.h include/fennec/containers/deque.h
include/fennec/containers/dynarray.h include/fennec/containers/dynarray.h
include/fennec/containers/graph.h include/fennec/containers/graph.h
@@ -96,7 +114,9 @@ add_library(fennec STATIC
include/fennec/containers/object_pool.h include/fennec/containers/object_pool.h
include/fennec/containers/optional.h include/fennec/containers/optional.h
include/fennec/containers/pair.h include/fennec/containers/pair.h
include/fennec/containers/priority_queue.h
include/fennec/containers/rdtree.h include/fennec/containers/rdtree.h
include/fennec/containers/sequence.h
include/fennec/containers/set.h include/fennec/containers/set.h
include/fennec/containers/traversal.h include/fennec/containers/traversal.h
include/fennec/containers/tuple.h include/fennec/containers/tuple.h
@@ -124,7 +144,7 @@ add_library(fennec STATIC
include/fennec/lang/type_sequences.h include/fennec/lang/type_sequences.h
include/fennec/lang/type_traits.h include/fennec/lang/type_traits.h
include/fennec/lang/type_transforms.h include/fennec/lang/type_transforms.h
include/fennec/lang/typeuuid.h include/fennec/lang/typed.h
include/fennec/lang/types.h include/fennec/lang/types.h
include/fennec/lang/utility.h include/fennec/lang/utility.h
include/fennec/lang/integer.h include/fennec/lang/integer.h
@@ -207,15 +227,19 @@ add_library(fennec STATIC
include/fennec/langproc/filesystem/file.h source/langproc/filesystem/file.cpp include/fennec/langproc/filesystem/file.h source/langproc/filesystem/file.cpp
include/fennec/langproc/filesystem/path.h source/langproc/filesystem/path.cpp include/fennec/langproc/filesystem/path.h source/langproc/filesystem/path.cpp
# Compile
include/fennec/langproc/compile/tokenizer.h
# PLATFORM ============================================================================================================= # PLATFORM =============================================================================================================
include/fennec/platform/interface/fwd.h include/fennec/platform/interface/fwd.h
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
include/fennec/platform/interface/display.h source/platform/interface/display.cpp include/fennec/platform/interface/window.h
include/fennec/platform/interface/gfxcontext.h
include/fennec/platform/interface/gfxsurface.h
# RENDERER =============================================================================================================
include/fennec/renderers/interface/gfxresourcepool.h
# EXTRA SOURCES ======================================================================================================== # EXTRA SOURCES ========================================================================================================
@@ -235,10 +259,16 @@ target_link_options(fennec PRIVATE ${FENNEC_PRIVATE_LINK_OPTIONS}) # Do not comp
target_link_libraries(fennec PRIVATE target_link_libraries(fennec PRIVATE
${FENNEC_LINK_LIBRARIES} ${FENNEC_LINK_LIBRARIES}
${FENNEC_SHARED_LIBRARIES}
cpptrace::cpptrace cpptrace::cpptrace
) )
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 ============================================================================================================== # DOXYGEN ==============================================================================================================

View File

@@ -18,7 +18,9 @@
# this script finds the compiler being used # this script finds the compiler being used
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(FENNEC_COMPILER "GCC") set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake") include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
endif() endif()

View File

@@ -18,8 +18,8 @@
# this script sets flags and variables for gnu and gnu-like compilers # this script sets flags and variables for gnu and gnu-like compilers
add_compile_options("-mxsave" "-Wall" "-Wextra" "-pedantic" "-Werror") add_compile_options("-Wall" "-Wextra" "-pedantic" "-Werror")
set(FENNEC_PRIVATE_LINK_OPTIONS "-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates") fennec_add_link_options("-nostdlib" "-fno-exceptions" "-fno-rtti" "-fdiagnostics-all-candidates")
list(APPEND FENNEC_COMPILE_DEFINITIONS _GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]]) fennec_add_definitions(_GLIBCXX_INCLUDE_NEXT_C_HEADERS=1 FENNEC_COMPILER_GCC=1 FENNEC_NO_INLINE=[[gnu::noinline]])

View File

@@ -34,9 +34,6 @@ macro(fennec_check_platform)
) )
if(FENNEC_USER_CLIENT) if(FENNEC_USER_CLIENT)
include("${FENNEC_SOURCE_DIR}/cmake/wayland.cmake")
fennec_check_wayland()
fennec_init_graphics() fennec_init_graphics()
endif() endif()

View File

@@ -31,27 +31,4 @@ if(TARGET OpenGL::GL AND TARGET GLEW::GLEW)
fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1) fennec_add_definitions(FENNEC_GRAPHICS_OPENGL=1)
else() else()
message(FATAL_ERROR "No Suitable OpenGL implementation found.") message(FATAL_ERROR "No Suitable OpenGL implementation found.")
endif()
if(FENNEC_GRAPHICS_WANT_EGL)
if(NOT TARGET OpenGL::EGL)
message(FATAL_ERROR "EGL Library not found.")
endif()
message(STATUS "Found EGL: ${OPENGL_egl_LIBRARY}")
fennec_add_link_libraries(OpenGL::EGL)
fennec_add_definitions(FENNEC_GRAPHICS_EGL=1)
fennec_add_sources(
include/fennec/platform/opengl/lib/fwd.h
include/fennec/platform/opengl/lib/enum.h
include/fennec/platform/opengl/lib/buffer.h
include/fennec/platform/opengl/lib/texture.h
include/fennec/platform/opengl/lib/vertex_array.h
include/fennec/platform/opengl/egl/fwd.h
include/fennec/platform/opengl/egl/context.h source/platform/opengl/egl/context.cpp
include/fennec/platform/opengl/egl/surface.h source/platform/opengl/egl/surface.cpp
)
endif() endif()

30
cmake/sdl.cmake Normal file
View File

@@ -0,0 +1,30 @@
# ======================================================================================================================
# 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/>.
# ======================================================================================================================
set(SDL_AUDIO OFF)
set(SDL_RENDER OFF)
add_subdirectory(${FENNEC_SOURCE_DIR}/external/SDL)
fennec_add_sources(
include/fennec/platform/sdl/sdlwindow.h
)
fennec_add_shared_libraries(
SDL3::SDL3-shared
)

View File

@@ -1,122 +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/>.
# ======================================================================================================================
# https://gist.github.com/mariobadr/acc3c8adf4b4e722705be38c3deac59a
# this script finds libwayland and dependencies
# some of this code is based on SDL3's use of wayland-scanner
macro(fennec_wayland_get_header _SCANNER _XML _FILE)
set(_WAYLAND_PROT_H_CODE "${WAYLAND_HEADERS_DIR}/${_FILE}-client-protocols.h")
set(_WAYLAND_PROT_C_CODE "${WAYLAND_SOURCES_DIR}/${_FILE}-client.c")
execute_process(
COMMAND ${_SCANNER} client-header "${_XML}" "${_WAYLAND_PROT_H_CODE}"
)
execute_process(
COMMAND ${_SCANNER} private-code "${_XML}" "${_WAYLAND_PROT_C_CODE}"
)
fennec_add_sources(${_WAYLAND_PROT_C_CODE} ${_WAYLAND_PROT_H_CODE})
endmacro()
macro(fennec_check_wayland)
set(WAYLAND_CLIENT_FOUND 0)
find_path(
WAYLAND_CLIENT_INCLUDE_DIR
NAMES wayland-client.h
)
find_library(
WAYLAND_CLIENT_LIBRARY
NAMES wayland-client libwayland-client
)
find_program(WAYLAND_SCANNER NAMES wayland-scanner)
# EGL is required
find_path(
WAYLAND_EGL_INCLUDE_DIR
NAMES wayland-egl.h
)
find_library(
WAYLAND_EGL_LIBRARY
NAMES wayland-egl libwayland-egl
)
if( (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARY AND WAYLAND_SCANNER)
AND (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARY))
message(STATUS "Found Wayland: ${WAYLAND_CLIENT_LIBRARY}")
set(WAYLAND_PROTOCOLS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/protocols)
set(WAYLAND_HEADERS_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/headers)
set(WAYLAND_SOURCES_DIR ${FENNEC_SOURCE_DIR}/include/fennec/platform/linux/wayland/lib/sources)
# Search for base protocol xml
find_file(WAYLAND_PROTOCOL NAMES wayland.xml PATHS /usr/share/wayland /usr/share/wayland-protocols)
file(COPY ${WAYLAND_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
# search for xdg protocols
find_file(XDG_SHELL_PROTOCOL NAMES xdg-shell.xml PATHS /usr/share/wayland-protocols/stable/xdg-shell)
file(COPY ${XDG_SHELL_PROTOCOL} DESTINATION ${WAYLAND_PROTOCOLS_DIR})
# include sub-dependencies
include("${FENNEC_SOURCE_DIR}/cmake/xkb.cmake")
fennec_check_xkb()
# generate protocols, based on SDL3
file(GLOB WAYLAND_PROTOCOLS_XML RELATIVE "${WAYLAND_PROTOCOLS_DIR}" "${WAYLAND_PROTOCOLS_DIR}/*.xml")
foreach(_XML IN LISTS WAYLAND_PROTOCOLS_XML)
get_filename_component(_FILE ${_XML} NAME_WLE)
fennec_wayland_get_header("${WAYLAND_SCANNER}" "${WAYLAND_PROTOCOLS_DIR}/${_XML}" "${_FILE}")
endforeach()
# Add sources and libraries
get_filename_component(
WAYLAND_CLIENT_LIBRARY
${WAYLAND_CLIENT_LIBRARY}
NAME
)
get_filename_component(
WAYLAND_EGL_LIBRARY
${WAYLAND_EGL_LIBRARY}
NAME
)
set(WAYLAND_CLIENT_FOUND 1)
set(WAYLAND_EGL_FOUND 1)
set(FENNEC_GRAPHICS_WANT_EGL 1)
fennec_add_sources(
# Dynamic Library Files
include/fennec/platform/linux/wayland/lib/sym.h
include/fennec/platform/linux/wayland/lib/wayland.h
include/fennec/platform/linux/wayland/lib/loader.h source/platform/linux/wayland/lib/loader.cpp
# Fennec Files
include/fennec/platform/linux/wayland/display.h source/platform/linux/wayland/display.cpp
include/fennec/platform/linux/wayland/window.h source/platform/linux/wayland/window.cpp
)
fennec_add_definitions(
FENNEC_HAS_WAYLAND=1
FENNEC_LIB_WAYLAND="${WAYLAND_CLIENT_LIBRARY}"
FENNEC_LIB_WAYLAND_EGL="${WAYLAND_EGL_LIBRARY}"
)
endif()
endmacro()

View File

@@ -1,58 +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/>.
# ======================================================================================================================
# this script finds libxkbcommon and dependencies
macro(fennec_check_xkb)
set(XKB_FOUND 0)
find_path(
XKB_INCLUDE_DIR
NAMES xkbcommon/xkbcommon.h
)
find_library(
XKB_LIBRARY
NAMES xkbcommon libxkbcommon
)
if(XKB_INCLUDE_DIR AND XKB_LIBRARY)
message(STATUS "Found XKB: ${XKB_LIBRARY}")
get_filename_component(
XKB_LIBRARY
${XKB_LIBRARY}
NAME
)
set(XKB_FOUND 1)
fennec_add_sources(
# Dynamic Library Files
include/fennec/platform/linux/xkb/lib/sym.h
include/fennec/platform/linux/xkb/lib/xkb.h
include/fennec/platform/linux/xkb/lib/loader.h source/platform/linux/xkb/lib/loader.cpp
# Fennec files
)
fennec_add_definitions(
FENNEC_HAS_XKB=1
FENNEC_LIB_XKB="${XKB_LIBRARY}"
)
endif()
endmacro()

File diff suppressed because it is too large Load Diff

67
examples/assert.cpp Normal file
View File

@@ -0,0 +1,67 @@
// =====================================================================================================================
// I release this example code into the public domain
// =====================================================================================================================
// This file contains code that tests the efficiency of the assert macro scheme in
// fennec engine. This is purely looking at the branching aspect and not the private
// assert definition. The code only uses passing values to see any performance overhead
// from the conditional
// This code is based on the example code that cppreference provides at
// https://en.cppreference.com/w/cpp/language/attributes/likely
// To my surprise, the difference between them is negligible.
// Even when n is a crazy number like one billion, there isn't a conclusive difference.
// I checked that it isn't the lambdas, they are optimized out.
// In debug mode, the results are to be expected; release < experimental < control
#include <cassert>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#define assert_c(expression) \
if(not(expression)) { \
std::abort(); \
}
#define assert_e(expression) \
if(not(expression)) [[unlikely]] { \
std::abort(); \
}
#define assert_r(expression) (static_cast<void> (0))
volatile int sink{}; // ensures a side effect
int main() {
auto benchmark = [](auto fun, auto rem) {
srand(0);
const auto start = std::chrono::high_resolution_clock::now();
for (auto size{1ULL}; size != 10'000'000ULL; ++size)
sink = fun(rand());
const std::chrono::duration<double> diff =
std::chrono::high_resolution_clock::now() - start;
std::cout << "Time: " << std::fixed << std::setprecision(6) << diff.count()
<< " sec " << rem << std::endl;
};
benchmark([](int x) {
assert_c(0 <= x && x <= RAND_MAX);
return x;
}, "control");
benchmark([](int x) {
assert_r(0 <= x && x <= RAND_MAX);
return x;
}, "release");
benchmark([](int x) {
assert_e(0 <= x && x <= RAND_MAX);
return x;
}, "experimental");
}

1
external/SDL vendored Submodule

Submodule external/SDL added at dee2414ee7

View File

@@ -371,7 +371,7 @@ class RDTreePrinter:
index += '' index += ''
index += '' index += ''
index += '[{}, {}]'.format(node, i) index += '[{}]'.format(node)
return index, value return index, value
@@ -389,6 +389,141 @@ class RDTreePrinter:
return self.Iterator(self.tree, 0, self.capacity) return self.Iterator(self.tree, 0, self.capacity)
# PRIORITY QUEUE =======================================================================================================
class PriorityQueuePrinter:
"""Print a fennec::rdtree"""
class Iterator:
def __init__(self, tree, node, capacity):
self.tree = tree
self.capacity = capacity
self.visit = deque()
self.skip = True
self.visit.append((node, 0, 0, node))
def __iter__(self):
return self
def __next__(self):
if len(self.visit) == 0:
raise StopIteration
node = self.visit[0][0]
i = self.visit[0][1]
depth = self.visit[0][2]
start = self.visit[0][3]
self.visit.popleft()
if node == start and not self.skip:
return self.__next__()
self.skip = False
value = self.tree[node]['_val']['key']
nnext = self.tree[node]['_val']['next']
child = self.tree[node]['_val']['child']
index = '' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
if nnext < self.capacity:
self.visit.appendleft((nnext, i + 1, depth, start))
if child < self.capacity:
self.visit.appendleft((child, 0, depth + 1, child))
self.skip = True
# ┌ ─ ├ └
if nnext != 18446744073709551615:
index += ''
else:
index += ''
index += ''
index += '[{}]'.format(node)
return index, value
def __init__(self, val):
self.tree = val['_table']['_table']['_alloc']['_data']
self.size = val['_table']['_size']
self.capacity = val['_table']['_table']['_alloc']['_capacity']
self.min = val['_min']
def to_string(self):
if self.size == 0:
return "{ empty }"
return "{ size = " + str(self.size) + " }"
def children(self):
return self.Iterator(self.tree, self.min, self.capacity)
# BINTREE ==============================================================================================================
class BinTreePrinter:
"""Print a fennec::bintree"""
class Iterator:
def __init__(self, tree, node, capacity):
self.tree = tree
self.capacity = capacity
self.visit = deque()
if capacity > 0:
self.visit.append((node, 0, 0))
def __iter__(self):
return self
def __next__(self):
if len(self.visit) == 0:
raise StopIteration
node = self.visit[0][0]
i = self.visit[0][1]
depth = self.visit[0][2]
parent = self.tree[node]['parent']
self.visit.popleft()
value = self.tree[node]['value']
left = self.tree[node]['left']
right = self.tree[node]['right']
if right < self.capacity:
self.visit.appendleft((right, 1, depth + 1))
if left < self.capacity:
self.visit.appendleft((left, 0, depth + 1))
index = '' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
if i == 0 and parent != 18446744073709551615 and self.tree[parent]['right'] != 18446744073709551615:
index += ''
else:
index += ''
index += ''
index += '[{}]'.format(node)
return index, value
def __init__(self, val):
self.tree = val['_table']['_data']
self.size = val['_size']
self.root = val['_root']
self.capacity = val['_table']['_capacity']
def to_string(self):
if self.size == 0:
return "{ empty }"
return "{ size = " + str(self.size) + " }"
def children(self):
return self.Iterator(self.tree, self.root, self.capacity)
# Graph ================================================================================================================ # Graph ================================================================================================================
class GraphPrinter: class GraphPrinter:
@@ -464,18 +599,21 @@ class GraphPrinter:
def register_printers(): def register_printers():
print("registering containers") print("registering containers")
pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers") pp = gdb.printing.RegexpCollectionPrettyPrinter("fennec::containers")
pp.add_printer('fennec::array', '^fennec::array<.*>$', ArrayPrinter) pp.add_printer('fennec::array', '^fennec::array<.*>$', ArrayPrinter)
pp.add_printer('fennec::deque', '^fennec::deque<.*>$', DequePrinter) pp.add_printer('fennec::deque', '^fennec::deque<.*>$', DequePrinter)
pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter) pp.add_printer('fennec::dynarray', '^fennec::dynarray<.*>$', DynArrayPrinter)
pp.add_printer('fennec::graph', '^fennec::graph<.*>$', GraphPrinter) pp.add_printer('fennec::graph', '^fennec::graph<.*>$', GraphPrinter)
pp.add_printer('fennec::list', '^fennec::list<.*>$', ListPrinter) pp.add_printer('fennec::list', '^fennec::list<.*>$', ListPrinter)
pp.add_printer('fennec::map', '^fennec::map<.*>$', MapPrinter) pp.add_printer('fennec::map', '^fennec::map<.*>$', MapPrinter)
pp.add_printer('fennec::object_pool', '^fennec::object_pool<.*>$', ObjectPoolPrinter) pp.add_printer('fennec::object_pool', '^fennec::object_pool<.*>$', ObjectPoolPrinter)
pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter) pp.add_printer('fennec::optional', '^fennec::optional<.*>$', OptionalPrinter)
pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter) pp.add_printer('fennec::pair', '^fennec::pair<.*>$', PairPrinter)
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter) pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter) pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter) pp.add_printer('fennec::bintree', '^fennec::bintree<.*>$', BinTreePrinter)
pp.add_printer('fennec::sequence', '^fennec::sequence<.*>$', BinTreePrinter)
pp.add_printer('fennec::priority_queue', '^fennec::priority_queue<.*>$', PriorityQueuePrinter)
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
return pp return pp
printer = register_printers() printer = register_printers()

View File

@@ -0,0 +1,832 @@
// =====================================================================================================================
// 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/containers/traversal.h>
#include <fennec/math/exponential.h>
#include <fennec/memory/allocator.h>
namespace fennec
{
///
/// \brief Structure defining a binary tree
/// \tparam TypeT The data type
/// \tparam AllocT An allocator class
template<typename TypeT, class AllocT = allocator<TypeT>>
struct bintree {
// Definitions =========================================================================================================
protected:
struct node;
public:
using value_t = TypeT;
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
static constexpr size_t npos = -1;
friend class iterator;
friend class const_iterator;
protected:
struct node {
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;
}
size_t& operator[](bool d) {
return d ? right : left;
}
};
using table_t = allocation<node, alloc_t>;
using freed_t = list<size_t, alloc_t>;
// Constructors & Destructor ===========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Default Constructor, initializes an empty tree
constexpr bintree()
: _table()
, _freed()
, _root(npos)
, _size(0) {
}
///
/// \brief Move Constructor, takes ownership of a tree
/// \param tree The tree to take ownership of
constexpr bintree(bintree&& tree) noexcept
: _table(fennec::move(tree._table))
, _freed(fennec::move(tree._freed))
, _root(tree._root)
, _size(tree._size) {
}
///
/// \brief Copy Constructor, copies a tree
/// \param tree The tree to copy
constexpr bintree(const bintree& tree)
: _table(tree._table)
, _freed(tree._freed)
, _root(tree._root)
, _size(tree._size) {
}
///
/// \brief Destructor, clears the tree
constexpr ~bintree() {
clear();
}
/// @}
// Properties ==========================================================================================================
public:
///
/// \returns The number of elements in the tree
constexpr size_t size() const {
return _size;
}
///
/// \returns `true` when there are no elements in the tree, `false` otherwise.
constexpr bool empty() const {
return _size == 0;
}
///
/// \returns The capacity of the underlying allocation
constexpr size_t capacity() const {
return _table.capacity();
}
///
/// \returns The next id to be returned by `insert` or `emplace`.
constexpr size_t next_id() const {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
}
return i;
}
///
/// \returns The next id to be returned by `insert` or `emplace`.
constexpr size_t root() const {
return _root;
}
// Navigation ==========================================================================================================
public:
/// \name Navigation
/// @{
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The parent of node `i`
constexpr size_t parent(size_t i) const {
return i == npos ? npos : _table[i].parent;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns The grandparent of node `i`
constexpr size_t grandparent(size_t i) const {
return parent(parent(i));
}
///
/// \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 {
return i == npos ? npos : _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 {
return i == npos ? npos : _table[i].right;
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \param dir The direction to go `true` for right, `false` for left
/// \returns The child in the direction specified by `dir`
constexpr size_t child(size_t i, bool dir) const {
return dir ? right(i) : left(i);
}
///
/// \details \f$O(1)\f$
/// \param i The node id
/// \returns `true` if `i` is the right node of `parent(i)`, `false` otherwise
constexpr bool direction(size_t i) const {
return i == npos ? false : i == right(parent(i));
}
///
/// \brief \f$O(1)\f$
/// \param i The id of the node
/// \returns The id of the sibling of `i`
constexpr size_t sibling(size_t i) const {
size_t p = parent(i);
size_t l = left(p);
size_t r = right(p);
return i == l ? r : l;
}
///
/// \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 {
return i >= _table.size() ? npos : _table[i].depth;
}
///
/// \brief \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the left-most node of `i`
constexpr size_t left_most(size_t i) const {
if (i >= _table.size()) {
return npos;
}
while (_table[i].left != npos) {
i = _table[i].left;
}
return i;
}
///
/// \brief \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the right-most node of `i`
constexpr size_t right_most(size_t i) const {
if (i >= _table.size()) {
return npos;
}
while (_table[i].right != npos) {
i = _table[i].right;
}
return i;
}
/// @}
// Access ==============================================================================================================
public:
/// \name 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) {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
}
///
/// \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 {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
}
/// @}
// Modifiers ===========================================================================================================
/// \name 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 Emplace 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 Move Right Insertion, constructs a new node as the right child of `p`
/// \details If the right 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_right(size_t p, value_t&& val) {
return this->_insert_right(p, fennec::forward<value_t>(val));
}
///
/// \brief Copy Right Insertion, constructs a new node as the right child of `p`
/// \details If the right 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_right(size_t p, const value_t& val) {
return this->_insert_right(p, val);
}
///
/// \brief Emplace Right Insertion, constructs a new node as the right child of `p`
/// \details If the right 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_right(size_t p, ArgsT&&...args) {
return this->_insert_right(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;
}
///
/// \brief Perform a Tree Rotation at `i` in the specified direction
/// \param i The root node for the rotation
/// \param dir The direction to rotate, `true` for right, `false` for left
constexpr size_t rotate(size_t sub, bool dir) {
if (sub >=_table.size()) {
return npos;
}
size_t sub_parent = parent(sub);
size_t new_root = child(sub, not dir);
size_t new_child = child(new_root, dir);
_child(sub, not dir) = new_child;
if (new_child != npos) {
_parent(new_child) = sub;
}
_child(new_root, dir) = sub;
_parent(new_root) = sub_parent;
_parent(sub) = new_root;
if (sub_parent != npos) {
_child(sub_parent, sub == right(sub_parent)) = new_root;
} else {
_root = new_root;
}
return new_root;
}
///
/// \brief Clears the tree, destroying all elements
constexpr void clear() {
list<size_t> queue;
if (_root != npos) {
queue.push_back(_root);
}
while (not queue.empty()) {
size_t i = queue.front();
queue.pop_front();
if (_table[i].left != npos) {
queue.push_front(_table[i].left);
}
if (_table[i].right != npos) {
queue.push_front(_table[i].right);
}
fennec::destruct(&_table[i]);
}
_size = 0;
_root = npos;
}
/// @}
// Traversal ===========================================================================================================
///
/// \brief Traverse the tree using a specified order and visiting functor
///
/// \details
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum
///
/// \tparam OrderT The order with which to traverse the tree.
/// \tparam VisitorT The visitor, should fulfill the signature `uint8_t visit(TypeT&, size_t)`
/// \param visit The visiting object
/// \param i The node to start at
template<typename OrderT, typename VisitorT>
constexpr void traverse(VisitorT&& visit, size_t i) {
OrderT order;
i = order(*this, i);
while (i != npos) {
uint8_t mode = traversal_control_continue;
if (_table[i].value) {
mode = visit(_table[i].value, i);
}
if (mode == traversal_control_break) {
break;
}
i = order[*this, i, mode];
}
}
struct breadth_first {
list<size_t> visit;
size_t head;
size_t operator()(const bintree&, size_t start) {
return head = start;
}
size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
size_t lft = tree.left(tree.parent(node));
size_t nxt = lft == node ? tree.right(tree.parent(node)) : npos;
size_t chd = tree.left(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
}
if (chd != npos && mode != traversal_control_jump_over) {
visit.push_back(chd);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct pre_order {
list<size_t> visit;
size_t head;
constexpr size_t operator()(const bintree&, size_t start) {
head = start;
return start;
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
size_t nxt = tree.right(tree.parent(node));
size_t chd = tree.left(node);
nxt = node == nxt ? npos : nxt;
if (nxt != npos && node != head) {
visit.push_front(nxt);
}
if (chd != npos && mode != traversal_control_jump_over) {
visit.push_front(chd);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct in_order {
list<size_t> visit;
size_t head;
constexpr size_t operator()(const bintree& tree, size_t start) {
head = start;
return tree.left_most(start);
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}
size_t parent = tree.parent(node);
size_t pright = tree.right(parent);
size_t next = tree.left_most(tree.right(node));
if (node != pright && parent != npos) {
visit.push_front(parent);
}
if (next != npos) {
visit.push_front(next);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct post_order {
list<size_t> visit;
size_t head;
constexpr size_t successor(const bintree& tree, size_t n) {
size_t s = tree.left_most(n);
while (n == s) {
size_t r = tree.right(n);
if (r != npos) {
n = r;
s = tree.left_most(n);
} else {
break;
}
}
return s == npos ? n : s;
}
constexpr size_t operator()(const bintree& tree, size_t start) {
head = start;
return this->successor(tree, start);
}
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) {
return npos;
}
size_t parent = tree.parent(node);
size_t pright = tree.right(parent);
if (node == pright) {
if (parent != npos) {
visit.push_front(parent);
}
} else if (pright != npos) {
visit.push_front(this->successor(tree, pright));
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
// Iterator ============================================================================================================
class iterator {
protected:
bintree* _tree;
in_order _order;
size_t _n;
public:
constexpr iterator(bintree* tree, size_t root)
: _tree(tree)
, _order()
, _n(_order(*tree, root)) {
}
constexpr iterator(bintree* tree, size_t root, size_t node)
: _tree(tree)
, _order()
, _n(node) {
_order(*tree, root);
}
size_t index() const {
return _n;
}
iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this;
}
value_t& operator*() {
return (*_tree)[_n];
}
value_t* operator->() {
return &(*_tree)[_n];
}
const value_t& operator*() const {
return (*_tree)[_n];
}
const value_t* operator->() const {
return &(*_tree)[_n];
}
constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n;
}
constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n;
}
};
// Fields ==============================================================================================================
protected:
table_t _table;
freed_t _freed;
size_t _root, _size;
// Helpers =============================================================================================================
constexpr size_t _next_free() {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
_freed.pop_front();
}
if (i >= _table.capacity()) {
_table.creallocate(2 * fennec::max(_table.capacity(), size_t(4)));
}
++_size;
return i;
}
template<typename...ArgsT>
constexpr size_t _insert_left(size_t p, ArgsT&&...args) {
size_t i = p >= capacity() ? npos : p;
i = i == npos ? _root : _left(i);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
} else {
size_t d = 1;
i = _next_free();
if (p != npos) {
d = depth(p) + 1;
_table[p].left = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...);
}
return i;
}
template<typename...ArgsT>
constexpr size_t _insert_right(size_t p, ArgsT&&...args) {
size_t i = p == npos ? _root : _right(p);
if (i != npos) {
_table[i].value = value_t(fennec::forward<ArgsT>(args)...);
if (p == npos || _root == npos) {
_root = i;
}
} else {
size_t d = 1;
i = _next_free();
if (p != npos) {
d = depth(p) + 1;
_table[p].right = i;
}
if (_root == npos) {
_root = i;
}
fennec::construct(&_table[i], p, npos, npos, d, fennec::forward<ArgsT>(args)...);
}
return i;
}
constexpr size_t& _parent(size_t i) {
return _table[i].parent;
}
constexpr size_t& _grandparent(size_t i) {
return _parent(parent(i));
}
constexpr size_t& _left(size_t i) {
return _table[i].left;
}
constexpr size_t& _right(size_t i) {
return _table[i].right;
}
constexpr size_t& _child(size_t i, bool dir) {
return dir ? _right(i) : _left(i);
}
constexpr size_t& _sibling(size_t i) {
size_t p = parent(i);
size_t& l = _left(p);
size_t& r = _right(p);
return i == l ? l : r;
}
};
}
#endif // FENNEC_CONTAINERS_BINTREE_H

View File

@@ -25,7 +25,7 @@ namespace fennec::detail
{ {
template <std::size_t I, typename T> template <size_t I, typename T>
struct _tuple_leaf struct _tuple_leaf
{ {
template <typename ArgT> template <typename ArgT>

View File

@@ -156,7 +156,9 @@ public:
// This constructor should not be invokable since moving is a single object operation and will cause undefined // This constructor should not be invokable since moving is a single object operation and will cause undefined
// behaviour when moving to multiple elements // behaviour when moving to multiple elements
constexpr dynarray(size_t n, TypeT&&) = delete; constexpr dynarray(size_t n, TypeT&& val)
: dynarray(n, fennec::copy(val)) {
};
/// ///
/// \brief Emplace Constructor /// \brief Emplace Constructor
@@ -432,6 +434,18 @@ public:
} }
} }
///
/// \brief Resize the dynarray, invoking the copy constructor for all new elements
/// \param n The new size in elements
/// \param val The value to fill with
constexpr void resize(size_t n, const TypeT& val) {
_alloc.creallocate(n);
while (_size < n) {
emplace_back(val);
}
}
/// ///
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation. /// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
constexpr void clear() { constexpr void clear() {

View File

@@ -140,6 +140,7 @@ public:
for (const value_t& it : l) { for (const value_t& it : l) {
this->push_back(it); this->push_back(it);
} }
return *this;
} }
/// ///
@@ -152,6 +153,7 @@ public:
_freed = fennec::move(l._freed); _freed = fennec::move(l._freed);
_root = l._root; _last = l._last; _root = l._root; _last = l._last;
_size = l._size; _size = l._size;
return *this;
} }
/// @} /// @}
@@ -164,15 +166,21 @@ public:
/// ///
/// \returns The size of the list in elements. /// \returns The size of the list in elements.
constexpr size_t size() const { return _size; } constexpr size_t size() const {
return _size;
}
/// ///
/// \returns The capacity of the list in elements. /// \returns The capacity of the list in elements.
constexpr size_t capacity() const { return _table.capacity(); } constexpr size_t capacity() const {
return _table.capacity();
}
/// ///
/// \returns `true` when the list is empty, `false` otherwise. /// \returns `true` when the list is empty, `false` otherwise.
constexpr bool empty() const { return _root == npos; } constexpr bool empty() const {
return _root == npos;
}
/// @} /// @}

View File

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

View File

@@ -48,8 +48,8 @@ struct object_pool {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using value_t = TypeT; using value_t = TypeT;
using elem_t = optional<TypeT>; using table_t = allocation<value_t, AllocT>;
using table_t = dynarray<elem_t, AllocT>; using freed_t = list<size_t, AllocT>;
// Constructors & Destructor =========================================================================================== // Constructors & Destructor ===========================================================================================
@@ -119,8 +119,7 @@ public:
/// \returns a reference to the object with id `i` /// \returns a reference to the object with id `i`
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
assert(_table[i], "Attempted to access Null Object."); return _table[i];
return *_table[i];
} }
/// ///
@@ -129,8 +128,7 @@ public:
/// \returns a const-qualified reference to the object with id `i` /// \returns a const-qualified reference to the object with id `i`
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
assert(_table[i], "Attempted to access Null Object."); return _table[i];
return *_table[i];
} }
/// @} /// @}
@@ -171,17 +169,24 @@ public:
/// \brief Erase an object from the pool /// \brief Erase an object from the pool
/// \param i The id of the object /// \param i The id of the object
constexpr void erase(size_t i) { constexpr void erase(size_t i) {
_table[i] = nullopt; fennec::destruct(&_table[i]);
_freed.push_back(i); _freed.push_back(i);
--_size; --_size;
} }
///
/// \brief Clear the object pool
constexpr void clear() {
dynarray<bool> free(capacity(), false);
_size = 0;
}
/// @} /// @}
private: private:
dynarray<elem_t, AllocT> _table; table_t _table;
list<size_t> _freed; freed_t _freed;
size_t _size; size_t _size;
size_t _next_free() { size_t _next_free() {
size_t next = _size; size_t next = _size;
@@ -196,10 +201,10 @@ private:
template<typename...ArgsT> template<typename...ArgsT>
size_t _insert(ArgsT&&...args) { size_t _insert(ArgsT&&...args) {
size_t i = _next_free(); size_t i = _next_free();
if (i >= _table.size()) { if (i >= _table.capacity()) {
_table.emplace_back(); _table.creallocate(fennec::max(_table.size() * 2, size_t(8)));
} }
_table[i].emplace(fennec::forward<ArgsT>(args)...); fennec::construct(&_table[i], fennec::forward<ArgsT>(args)...);
return i; return i;
} }
}; };

View File

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

View File

@@ -95,19 +95,33 @@ struct pair {
/// ///
/// \brief Copy Constructor, copies both elements /// \brief Copy Constructor, copies both elements
constexpr pair(const pair&) = default; constexpr pair(const pair& pair)
: first(fennec::copy(pair.first))
, second(fennec::copy(pair.second)) {
}
/// ///
/// \brief Move Constructor, moves both elements /// \brief Move Constructor, moves both elements
constexpr pair(pair&&) noexcept = default; constexpr pair(pair&& pair) noexcept
: first(fennec::move(pair.first))
, second(fennec::move(pair.second)) {
}
/// ///
/// \brief Copy Assignment, copies both elements /// \brief Copy Assignment, copies both elements
constexpr pair& operator=(const pair&) = default; constexpr pair& operator=(const pair& pair) {
first = fennec::copy(pair.first);
second = fennec::copy(pair.second);
return *this;
}
/// ///
/// \brief Move Assignment, moves both elements /// \brief Move Assignment, moves both elements
constexpr pair& operator=(pair&&) noexcept = default; constexpr pair& operator=(pair&& pair) {
first = fennec::move(pair.first);
second = fennec::move(pair.second);
return *this;
}
/// @} /// @}

View File

@@ -0,0 +1,193 @@
// =====================================================================================================================
// 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 priority_queue.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_PRIORITY_QUEUE_H
#define FENNEC_CONTAINERS_PRIORITY_QUEUE_H
#include <fennec/containers/object_pool.h>
#include <fennec/lang/compare.h>
#include <fennec/lang/types.h>
#include <fennec/memory/allocator.h>
// Binary heaps are just kinda busted.
// In-array binary heaps are one of the most efficient data structures for computers
// -> Cache Locality
// -> log(n) runtime
// -> No auxiliary structures or constant runtimes
// -> Only needs an extra byte for color
//
// I tried just about every heap under the sun
// -> strict fibonacci heap, got blown out of the water by std::priority_queue
// -> fibonacci heap, got blown out of the water by std::priority_queue
// -> binomial heap, on-par with std::set, blown out of the water by std::priority_queue
//
// Then I relented and fell back to ye old binary heap
// This implementation roughly matches gcc's std::priority_queue
namespace fennec
{
template<typename ValueT, class CompareT = less<ValueT>, class AllocT = allocator<ValueT>>
struct priority_queue {
// Definitions & Constants =============================================================================================
public:
using value_t = ValueT;
using compare_t = CompareT;
using alloc_t = allocation<value_t, AllocT>;
static constexpr size_t npos = -1;
private:
constexpr size_t left(size_t n) const {
n = n * 2 + 1;
return n >= _size ? npos : n;
}
constexpr size_t right(size_t n) const {
n = n * 2 + 2;
return n >= _size ? npos : n;
}
constexpr size_t parent(size_t n) const {
return n == 0 ? npos : (n - 1) / 2;
}
// Constructors & Destructor ===========================================================================================
public:
constexpr priority_queue()
: _size(0) {
}
constexpr ~priority_queue() {
while (_size > 0) {
--_size;
fennec::destruct(&_table[_size]);
}
}
// Properties ==========================================================================================================
constexpr size_t size() const {
return _size;
}
constexpr size_t capacity() const {
return _table.capacity();
}
constexpr bool empty() const {
return size() == 0;
}
// Access ==============================================================================================================
constexpr const value_t& front() const {
return _table[0];
}
// Modifiers ===========================================================================================================
constexpr void push(const value_t& key) {
this->_insert(key);
}
constexpr void push(value_t&& key) {
this->_insert(fennec::forward<value_t>(key));
}
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
this->_insert(fennec::forward<ArgsT>(args)...);
}
constexpr void pop() {
fennec::swap(_table[0], _table[--_size]);
fennec::destruct(&_table[_size]);
_fix_erase(0);
}
// Members =============================================================================================================
private:
compare_t _compare;
alloc_t _table;
size_t _size;
// Helpers =============================================================================================================
template<typename...ArgsT>
constexpr void _insert(ArgsT&&...args) {
if (_size == _table.capacity()) {
_expand();
}
fennec::construct(&_table[_size], fennec::forward<ArgsT>(args)...);
_fix_insert(_size++);
}
constexpr void _expand() {
_table.reallocate((_table.capacity() + 1) * 2 - 1);
}
constexpr size_t _min(size_t a, size_t b) {
if (a == npos) { return b; }
if (b == npos) { return a; }
return _compare(_table[a], _table[b]) ? a : b;
}
void _fix_insert(size_t n) {
size_t p = parent(n);
while (p != npos && _compare(_table[n], _table[p])) {
fennec::swap(_table[n], _table[p]);
n = p;
p = parent(n);
}
}
void _fix_erase(size_t n) {
size_t c = _min(left(n), right(n));
while (n != npos && c != npos && _compare(_table[c], _table[n])) {
fennec::swap(_table[c], _table[n]);
n = c;
c = _min(left(n), right(n));
}
}
};
}
#endif // FENNEC_CONTAINERS_PRIORITY_QUEUE_H

View File

@@ -58,7 +58,7 @@ public:
protected: protected:
struct node { struct node {
optional<TypeT> value; optional<value_t> value;
size_t parent, child, prev, next; size_t parent, child, prev, next;
size_t depth, num_children; size_t depth, num_children;
@@ -414,7 +414,7 @@ public:
/// \param visit The visiting object /// \param visit The visiting object
/// \param i The node to start at /// \param i The node to start at
template<typename OrderT, typename VisitorT> template<typename OrderT, typename VisitorT>
void traverse(VisitorT&& visit, size_t i = root) { constexpr void traverse(VisitorT&& visit, size_t i = root) {
OrderT order; OrderT order;
i = order(*this, i); i = order(*this, i);
while (i != npos) { while (i != npos) {
@@ -429,16 +429,52 @@ public:
} }
} }
struct pre_order { struct breadth_first {
list<size_t> visit; list<size_t> visit;
size_t head; size_t head;
size_t operator()(const rdtree&, size_t start) { constexpr size_t operator()(const rdtree&, size_t start) {
head = start; head = start;
return start; return start;
} }
size_t operator[](const rdtree& tree, size_t node, uint8_t mode) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
if (node == npos) {
return npos;
}
size_t nxt = tree.next(node);
size_t chd = tree.next(node);
if (nxt != npos && node != head) {
visit.push_front(nxt);
}
if (chd != npos && mode != traversal_control_jump_over) {
visit.push_back(chd);
}
if (not visit.empty()) {
node = visit.front();
visit.pop_front();
} else {
node = npos;
}
return node;
}
};
struct pre_order {
list<size_t> visit;
size_t head;
constexpr size_t operator()(const rdtree&, size_t start) {
head = start;
return start;
}
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
if (node == npos) { if (node == npos) {
return npos; return npos;
} }
@@ -469,12 +505,12 @@ public:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head;
size_t operator()(const rdtree& tree, size_t start) { constexpr size_t operator()(const rdtree& tree, size_t start) {
head = start; head = start;
return tree.left_most(start); return tree.left_most(start);
} }
size_t operator[](const rdtree& tree, size_t node, uint8_t) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
} }
@@ -507,12 +543,12 @@ public:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head;
size_t operator()(const rdtree& tree, size_t start) { constexpr size_t operator()(const rdtree& tree, size_t start) {
head = start; head = start;
return tree.left_most(start); return tree.left_most(start);
} }
size_t operator[](const rdtree& tree, size_t node, uint8_t) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
} }

View File

@@ -0,0 +1,600 @@
// =====================================================================================================================
// 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 sequence.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_SEQUENCE_H
#define FENNEC_CONTAINERS_SEQUENCE_H
#include <fennec/containers/bintree.h>
#include <fennec/containers/bintree.h>
#include <fennec/containers/pair.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/lang/compare.h>
#include <fennec/memory/allocator.h>
// https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
// https://www.geeksforgeeks.org/dsa/insertion-in-red-black-tree/
// Uncertain how I managed to do this, but this data structure has
// A 50%-100% performance increase over std::set when running Dijkstra's
//
// Guesses:
// -> I likely make some assumptions that std::set doesn't
// -> Cache locality
// -> Simplified rotation and coloring logic
//
// Some of the implementations I have seen have multiple levels
// of if statements based on directionality which causes branching.
// I use const-expressions that reduce down to cmov instructions
namespace fennec
{
///
///
/// \brief wrapper for ordered sets of elements, called sequences in mathematics
/// \details
/// This data-structure behaves like an ordered-set, but does not use pointers, instead storing the table in-array
///
/// | Property | Value |
/// |:----------:|:---------------:|
/// | stable | ⛔ |
/// | dynamic | ✅ |
/// | homogenous | ✅ |
/// | distinct | ✅ |
/// | ordered | ✅ |
/// | space | \f$O(N)\f$ |
/// | linear | ✅ |
/// | access | \f$O(\log N)\f$ |
/// | find | \f$O(\log N)\f$ |
/// | insertion | \f$O(\log N)\f$ |
/// | deletion | \f$O(\log N)\f$ |
///
/// \tparam TypeT The type to contain
/// \tparam CompareT Function for comparing two values
/// \tparam AllocT An allocator class
template<typename TypeT, typename CompareT = less<TypeT>, class AllocT = allocator<pair<TypeT, bool>>>
struct sequence : protected bintree<pair<TypeT, bool>, AllocT> {
// Definitions =========================================================================================================
protected:
struct node;
public:
using value_t = TypeT;
using node_t = pair<TypeT, bool>;
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
using base_t = bintree<pair<TypeT, bool>, AllocT>;
using compare_t = CompareT;
static constexpr size_t npos = -1;
enum color_ : bool {
black = false,
red = true,
};
class iterator;
protected:
using typename base_t::in_order;
using base_t::left;
using base_t::right;
using base_t::child;
using base_t::direction;
using base_t::parent;
using base_t::grandparent;
using base_t::sibling;
using base_t::left_most;
using base_t::right_most;
using base_t::insert_left;
using base_t::insert_right;
using base_t::rotate;
using base_t::rotate_left;
using base_t::rotate_right;
using base_t::_table;
using base_t::_freed;
using base_t::_root;
using base_t::_size;
// Constructors & Destructors ==========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Default Constructor, initializes an empty sequence
constexpr sequence() = default;
///
/// \brief Move Constructor, takes ownership of a sequence
constexpr sequence(sequence&&) noexcept = default;
///
/// \brief Copy Constructor, copies a sequence
constexpr sequence(const sequence&) = default;
///
/// \brief Default Destructor, destructs elements *in-order*
constexpr ~sequence() {
this->clear();
}
/// @}
// Search ==============================================================================================================
public:
/// \name Search
/// @{
///
/// \brief Value Find Function, finds the iterator position for `val`, otherwise returns `end()`
/// \param val The value to find
/// \returns An iterator at the value
constexpr iterator find(const value_t& val) {
size_t node = _root;
while (node != npos) {
if (_compare(val, _value(node))) {
node = left(node);
} else if (_compare(_value(node), val)) {
node = right(node);
} else {
return sequence::iterator(this, _root, node);
}
}
return sequence::iterator(this, _root, node);
}
///
/// \brief Value Contains Function, checks if the sequence contains a value
/// \param val The value to find
/// \returns `true` if `val` is in the sequence, `false` otherwise
bool contains(const value_t& val) {
return find(val) != end();
}
/// @}
// Properties ==========================================================================================================
public:
/// \name Properties
/// @{
///
/// \returns The number of elements in the sequence
using base_t::size;
///
/// \returns The capacity of the underlying allocation
using base_t::capacity;
///
/// \returns `true` when there are no elements in the sequence, `false` otherwise.
using base_t::empty;
/// @}
// Modifiers ===========================================================================================================
public:
/// \name Modifiers
/// @{
///
/// \brief Move Insertion, moves `val` into the sequence
/// \param val The value to insert
constexpr void insert(value_t&& val) {
size_t i = _insert_bst(fennec::forward<value_t>(val));
_fix_insert(i);
}
///
/// \brief Copy Insertion, inserts a copy of `val` into the sequence
/// \param val The value to insert
constexpr void insert(const value_t& val) {
size_t i = _insert_bst(val);
_fix_insert(i);
}
///
/// \brief Emplacement, constructs and adds a value into the sequence
/// \tparam ArgsT The argument types
/// \param args The arguments to construct with
template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) {
size_t i = _insert_bst(fennec::forward<ArgsT>(args)...);
_fix_insert(i);
}
constexpr void erase(const value_t& val) {
_erase(find(val).index());
}
///
/// \brief Destructs all elements, *in-order*, contained in the sequence
constexpr void clear() {
in_order order;
size_t node = order(*this, _root);
while (node != npos) {
size_t erase = node;
node = order[*this, node, traversal_control_continue];
fennec::destruct(&_table[erase]);
}
_size = 0;
}
/// @}
// Iterator ============================================================================================================
///
/// \returns An iterator at the smallest element in the sequence
constexpr iterator begin() {
return sequence::iterator(this, _root);
}
///
/// \returns An iterator after the largest element in the sequence
constexpr iterator end() {
return sequence::iterator(this, _root, npos);
}
class iterator : public base_t::iterator {
protected:
using base_t::iterator::_n;
using base_t::iterator::_tree;
public:
using base_t::iterator::iterator;
value_t& operator*() {
return base_t::iterator::operator*().first;
}
const value_t& operator*() const {
return base_t::iterator::operator*().first;
}
value_t* operator->() {
return &base_t::iterator::operator*().first;
}
const value_t* operator->() const {
return &base_t::iterator::operator*().firstf;
}
};
// Fields ==============================================================================================================
protected:
compare_t _compare;
inline static bool color_sink = red;
inline static value_t value_sink;
// Helpers =============================================================================================================
protected:
using base_t::_left;
using base_t::_right;
using base_t::_parent;
using base_t::_sibling;
using base_t::_child;
constexpr value_t& _value(size_t i) {
return _table[i].value.first;
}
constexpr const value_t& _value(size_t i) const {
return _table[i].value.first;
}
constexpr bool& _color(size_t i) {
return _table[i].value.second;
}
constexpr bool color(size_t i) const {
return i == npos ? false : _table[i].value.second;
}
constexpr void _recolor(size_t n) {
bool c = !color(n);
if (n == _root) { // Only recolor if not the root node
_color(n) = c;
}
_color(left(n)) = !_color(left(n)) ;
_color(right(n)) = !_color(right(n));
}
// run-of-the-mill bst insert
template<typename...ArgsT>
constexpr size_t _insert_bst(ArgsT&&...args) {
value_t val(fennec::forward<ArgsT>(args)...);
if (_root == npos) {
return _root = insert_left(npos, node_t(fennec::move(val), red));
}
size_t i = _root;
size_t p = npos;
while (i != npos) {
p = i;
if (_compare(val, _value(i))) {
i = left(i);
} else if (_compare(_value(i), val)) {
i = right(i);
} else {
return i;
}
}
if (_compare(val, _value(p))) {
return insert_left(p, node_t(fennec::move(val), red));
} else {
return insert_right(p, node_t(fennec::move(val), red));
}
}
// This makes some cheats given that the structure is modified only by internal functions
// If such is the case, ONLY LL, LR, RL, and RR will show up
// Then we just need to handle splitting a 4-node
constexpr void _fix_insert(size_t n) {
size_t p = parent(n);
while (color(p) != black) {
size_t g = parent(p);
size_t u = sibling(p);
size_t d = direction(n);
size_t r = direction(p);
// Split 4 node
if (color(u) == red) {
_recolor(g);
n = p;
p = g;
continue;
}
// LR & RL case
if (d != r) {
rotate(p, r);
}
// LL & RR case
rotate(g, not r);
n = parent(n);
p = parent(n);
}
}
constexpr void _transplant(size_t u, size_t v) {
size_t p = parent(u);
if (p == npos) {
_root = v;
} else if (u == left(p)) {
_left(p) = v;
} else {
_right(p) = v;
}
_parent(v) = _parent(u);
}
constexpr void _swap_val(size_t a, size_t b) {
fennec::swap(_value(a), _value(b));
}
constexpr size_t _replace(size_t x) {
size_t l = left(x);
size_t r = right(x);
// Both are null
if (l == r) {
return npos;
}
if (l == npos) {
return r;
} else if (r == npos) {
return l;
} else {
return left_most(right(x));
}
}
constexpr size_t _red_child(size_t x) {
size_t l = left(x);
size_t r = right(x);
if (color(l) == red) {
return l;
}
if (color(r) == red) {
return r;
}
return npos;
}
// This is an implementation based on the C code in
// the wikipedia article adapted to this framework
constexpr void _fix_erase(size_t n) {
size_t p = parent(n);
size_t s, sc, sf;
bool d = n == right(p);
_child(p, d) = npos;
goto start_balance;
do {
d = n == right(p);
start_balance:
s = child(p, !d);
sf = child(s, !d);
sc = child(s, d);
if (color(s) == red) {
// Case 3
rotate(p, d);
_color(p) = red;
_color(s) = black;
// Fix pointers
s = sc;
sf = child(s, !d);
sc = child(s, d);
if (color(sf) == red) {
goto case_6;
}
if (color(sc) == red) {
goto case_5;
}
// Case 4
if (color(p) == red) {
if (s != npos) {
_color(s) = red;
}
_color(p) = black;
return;
}
}
if (color(sf) == red) {
goto case_6;
}
if (color(sc) == red) {
goto case_5;
}
// Case 4
if (color(p) == red) {
if (s != npos) {
_color(s) = red;
}
_color(p) = black;
return;
}
// Case 1
if (p == npos) {
return;
}
// Case 2
if (s != npos) {
_color(s) = red;
}
n = p;
} while ((p = parent(n)) != npos);
return; //
case_5:
rotate(s, !d);
_color(s) = red;
_color(sc) = black;
sf = s;
s = sc;
case_6:
rotate(p, d);
_color(s) = color(p);
_color(p) = black;
_color(sf) = black;
}
constexpr void _erase(size_t n) {
if (n == npos) {
return;
}
size_t l = left(n);
size_t r = right(n);
// 2 children
if (l != npos && r != npos) {
size_t s = left_most(r);
_swap_val(n, s);
n = s;
l = left(n);
r = right(n);
}
size_t p = parent(n);
bool d = n == right(p);
size_t c = l != npos ? l : r;
// Single child
if (c != npos) {
_parent(c) = p;
}
// Handles root cases
if (p == npos) {
_root = c;
if (c == npos) {
fennec::destruct(&_table[n]);
_freed.push_back(n);
--_size;
return;
} else {
_color(c) = black;
}
}
// Single Child, Red, and Root cases
if (p == npos || c != npos || color(n) == red) {
if (p != npos) {
_child(p, d) = c;
}
fennec::destruct(&_table[n]);
_freed.push_back(n);
--_size;
return;
}
_fix_erase(n);
fennec::destruct(&_table[n]);
_freed.push_back(n);
--_size;
}
};
}
#endif // FENNEC_CONTAINERS_SEQUENCE_H

View File

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

View File

@@ -106,6 +106,7 @@
/// </table> /// </table>
/// ///
#include <fennec/lang/intrinsics.h>
#include <fennec/lang/type_transforms.h> #include <fennec/lang/type_transforms.h>
#include <fennec/lang/detail/_type_traits.h> #include <fennec/lang/detail/_type_traits.h>
@@ -181,7 +182,7 @@ template<typename T> constexpr bool_t is_null_pointer_v = is_null_pointer<T>::va
// fennec::is_array ==================================================================================================== // fennec::is_array ====================================================================================================
#if FENNEC_HAS_BUILTIN_IS_ARRAY #ifdef FENNEC_BUILTIN_IS_ARRAY
/// ///
/// \brief check if \p T is of an array type /// \brief check if \p T is of an array type

View File

@@ -0,0 +1,96 @@
// =====================================================================================================================
// 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 tokenizer.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_LANGPROC_FORMAT_TOKENIZER_H
#define FENNEC_LANGPROC_FORMAT_TOKENIZER_H
#include <fennec/containers/list.h>
#include <fennec/langproc/strings/string.h>
//
// escape sequences are tricky, sometimes they must be separated by white space,
// other times they don't. Requiring a list of all possible escape sequences is unrealistic.
// We need to allow the user of this struct to specify rules for escape sequences. Here are some basic rules:
//
// An escape sequence is marked by an escape character, e.g. %, \, {{
// Multiple escape characters may be used in a single tokenizer and will have different rules
// Escape characters may also be operators, brackets, or quotes
// Escape sequences may contain operators, brackets, or quotes
//
// Here are a few examples of escape sequences from various formats and languages
// C: \\, \n, \0, \u200b
// PrintF: %s, %2.2f
// Python FMT: {{, }}
// SPSS: ''
//
namespace fennec
{
struct escape_sequence {
virtual size_t operator[](const std::string& str, size_t i) = 0;
};
struct tokenizer {
using escseq = escape_sequence*;
using escmap = map<char, escape_sequence*>;
string delimiter; // markers that separate tokens
string operators; // operators are treated as individual tokens
string brackets; // characters that mark brackets
string quotes; // characters that mark a string sequence, entire string sequence is treated as one token
escmap escapes; // characters that mark the start of an escape sequence and validate them
enum token_ : uint8_t {
token_string = 0,
token_newline = 1,
token_escaped = 2,
token_operator = 3,
token_bracket = 4,
token_quoted = 5,
};
using token = pair<string, uint8_t>;
private:
// list<token> operator()(const string& line) {
// list<token> res;
//
// for (size_t i = 0; i < )
//
// return res;
// }
private:
};
}
#endif // FENNEC_LANGPROC_FORMAT_TOKENIZER_H

View File

@@ -250,9 +250,6 @@ public:
// Binary Read Operations ============================================================================================== // Binary Read Operations ==============================================================================================
char getc();
wchar_t getwc();
size_t read(void* data, size_t size, size_t n); size_t read(void* data, size_t size, size_t n);
template<typename T> template<typename T>
@@ -265,9 +262,6 @@ public:
return read(static_cast<void*>(data), sizeof(T), n); return read(static_cast<void*>(data), sizeof(T), n);
} }
string getline();
wstring getwline();
// Binary Write Operations ============================================================================================= // Binary Write Operations =============================================================================================
@@ -297,6 +291,15 @@ public:
} }
// Read Operations =====================================================================================================
char getc();
wchar_t getwc();
string getline();
wstring getwline();
// Printing Operations ================================================================================================= // Printing Operations =================================================================================================

View File

@@ -58,6 +58,7 @@ struct cstring
{ {
public: public:
static constexpr size_t npos = -1; static constexpr size_t npos = -1;
using char_t = char;
// Constructors ======================================================================================================== // Constructors ========================================================================================================

View File

@@ -47,6 +47,7 @@ struct _string
{ {
public: public:
static constexpr size_t npos = -1; static constexpr size_t npos = -1;
using char_t = char;
using alloc_t = allocation<char, AllocT>; using alloc_t = allocation<char, AllocT>;
@@ -197,7 +198,7 @@ public:
if (i >= size()) { // bounds check if (i >= size()) { // bounds check
return -1; return -1;
} }
n = fennec::min(n, fennec::max(_str, str.size()) + 1); n = fennec::min(n, fennec::max(size(), str.size()) + 1);
return ::strncmp(_str + i, str, n); return ::strncmp(_str + i, str, n);
} }
@@ -216,10 +217,23 @@ public:
return ::strncmp(_str + i, str.data(), n); return ::strncmp(_str + i, str.data(), n);
} }
constexpr bool operator==(const cstring& str) const {
return compare(str) == 0;
}
constexpr bool operator==(const _string& str) const { constexpr bool operator==(const _string& str) const {
return compare(str) == 0; return compare(str) == 0;
} }
///
/// \brief Check if the string contains a character
/// \param c
/// \param i
/// \return
constexpr bool contains(char c, size_t i = 0) const {
return find(c, i) != size();
}
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of `c` in the string
/// \param c the character to find /// \param c the character to find
@@ -242,7 +256,7 @@ public:
return size(); return size();
} }
const char* loc = ::strstr(_str, str); const char* loc = ::strstr(_str, str._str);
return loc ? loc - _str : size(); return loc ? loc - _str : size();
} }
@@ -325,7 +339,7 @@ public:
/// \param n the number of characters /// \param n the number of characters
/// \return /// \return
constexpr _string substring(size_t i, size_t n = npos) const { constexpr _string substring(size_t i, size_t n = npos) const {
if (i >= size()) { if (i >= size() || n == 0) {
return _string(""); return _string("");
} }
n = fennec::min(n, size() - i); n = fennec::min(n, size() - i);
@@ -420,6 +434,25 @@ public:
} }
// Iteration ===========================================================================================================
constexpr char* begin() {
return _str.data();
}
constexpr const char* begin() const {
return _str.data();
}
constexpr char* end() {
return _str.data() + _str.capacity();
}
constexpr const char* end() const {
return _str.data() + _str.capacity();
}
private: private:
alloc_t _str; alloc_t _str;
}; };

View File

@@ -60,6 +60,7 @@ struct wcstring
{ {
public: public:
static constexpr size_t npos = -1; static constexpr size_t npos = -1;
using char_t = wchar_t;
// Constructors ======================================================================================================== // Constructors ========================================================================================================

View File

@@ -47,6 +47,7 @@ struct _wstring
{ {
public: public:
static constexpr size_t npos = -1; static constexpr size_t npos = -1;
using char_t = wchar_t;
using alloc_t = allocation<wchar_t, AllocT>; using alloc_t = allocation<wchar_t, AllocT>;
@@ -216,10 +217,23 @@ public:
return ::wcsncmp(_str + i, str.data(), n); return ::wcsncmp(_str + i, str.data(), n);
} }
constexpr bool operator==(const wcstring& str) const {
return compare(str) == 0;
}
constexpr bool operator==(const _wstring& str) const { constexpr bool operator==(const _wstring& str) const {
return compare(str) == 0; return compare(str) == 0;
} }
///
/// \brief Check if the string contains a character
/// \param c
/// \param i
/// \return
constexpr bool contains(char c, size_t i = 0) const {
return find(c, i) != size();
}
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of `c` in the string
/// \param c the wchar_tacter to find /// \param c the wchar_tacter to find

View File

@@ -306,8 +306,8 @@ public:
// Quaternion Quaternion Arithmetic Operators ========================================================================== // Quaternion Quaternion Arithmetic Operators ==========================================================================
constexpr friend quaternion operator+(const quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t operator+(const quat_t& lhs, const quat_t& rhs) {
return quaternion( return quat_t(
lhs.w + rhs.w, lhs.w + rhs.w,
lhs.x + rhs.x, lhs.x + rhs.x,
lhs.y + rhs.y, lhs.y + rhs.y,
@@ -315,8 +315,8 @@ public:
); );
} }
constexpr friend quaternion operator-(const quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t operator-(const quat_t& lhs, const quat_t& rhs) {
return quaternion( return quat_t(
lhs.w - rhs.w, lhs.w - rhs.w,
lhs.x - rhs.x, lhs.x - rhs.x,
lhs.y - rhs.y, lhs.y - rhs.y,
@@ -324,8 +324,8 @@ public:
); );
} }
constexpr friend quaternion operator*(const quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t operator*(const quat_t& lhs, const quat_t& rhs) {
return quaternion( return quat_t(
lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z, lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z * rhs.z,
lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z * rhs.y, lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z * rhs.y,
lhs.w*rhs.y - lhs.x*rhs.z + lhs.y*rhs.w + lhs.z * rhs.x, lhs.w*rhs.y - lhs.x*rhs.z + lhs.y*rhs.w + lhs.z * rhs.x,
@@ -336,7 +336,7 @@ public:
// Quaternion Quaternion Arithmetic Assignment Operators =============================================================== // Quaternion Quaternion Arithmetic Assignment Operators ===============================================================
constexpr friend quaternion& operator+=(quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t& operator+=(quat_t& lhs, const quat_t& rhs) {
lhs.w += rhs.w; lhs.w += rhs.w;
lhs.x += rhs.x; lhs.x += rhs.x;
lhs.y += rhs.y; lhs.y += rhs.y;
@@ -344,7 +344,7 @@ public:
return lhs; return lhs;
} }
constexpr friend quaternion& operator-=(quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t& operator-=(quat_t& lhs, const quat_t& rhs) {
lhs.w -= rhs.w; lhs.w -= rhs.w;
lhs.x -= rhs.x; lhs.x -= rhs.x;
lhs.y -= rhs.y; lhs.y -= rhs.y;
@@ -352,7 +352,7 @@ public:
return lhs; return lhs;
} }
constexpr friend quaternion& operator*=(quaternion& lhs, const quaternion& rhs) { constexpr friend quat_t& operator*=(quat_t& lhs, const quat_t& rhs) {
return lhs = lhs * rhs; return lhs = lhs * rhs;
} }

View File

@@ -280,7 +280,7 @@ public:
/// \details This simply acts as a proxy for allocating memory. It does not call any constructors or /// \details This simply acts as a proxy for allocating memory. It does not call any constructors or
/// initialize any values as if they were the provided data type. Any operations present work /// initialize any values as if they were the provided data type. Any operations present work
/// only on individual bytes. /// only on individual bytes.
template<typename T, class AllocT> template<typename T, class AllocT = allocator<T>>
struct allocation struct allocation
{ {
public: public:

View File

@@ -1,83 +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/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_INTERFACE_DISPLAY_H
#define FENNEC_PLATFORM_INTERFACE_DISPLAY_H
#include <fennec/langproc/strings/string.h>
#include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>
namespace fennec
{
class display : public typed<display>
{
public:
struct pixel_format {
uint8_t depth;
uint8_t r, g, b;
};
struct config {
pixel_format format;
};
virtual bool connected() const = 0;
virtual ~display();
virtual window* create_window(window* parent) = 0;
const pixel_format& get_color_format() const {
return _config.format;
}
virtual void select_context();
virtual void* get_native_handle() = 0;
platform* get_platform() { return _platform; }
gfxcontext* get_context() { return _context; }
const string name;
protected:
platform* _platform;
gfxcontext* _context;
config _config;
template<typename DisplayT>
explicit display(platform* platform, const cstring& name, DisplayT* type)
: typed(type)
, name(name)
, _platform(platform)
, _context(nullptr)
, _config {
.format = {
.depth = 24,
.r = 8,
.g = 8,
.b = 8,
}
} {
}
};
}
#endif // FENNEC_PLATFORM_INTERFACE_DISPLAY_H

View File

@@ -22,12 +22,7 @@
namespace fennec namespace fennec
{ {
class platform; // Handles OS level functionality
class display; // Handles display protocols
class window; // Handles window surfaces of the display protocol class window; // Handles window surfaces of the display protocol
class inputdevice; // Handles input devices
class gfxcontext; // Handle Driver Contexts, i.e. EGL, WGL, VkWayland, etc.
class gfxsurface; // Handle surface targets for windows
} }

View File

@@ -20,10 +20,12 @@
#define FENNEC_PLATFORM_INTERFACE_PLATFORM_H #define FENNEC_PLATFORM_INTERFACE_PLATFORM_H
#include <fennec/containers/list.h> #include <fennec/containers/list.h>
#include <fennec/containers/sequence.h>
#include <fennec/langproc/strings/cstring.h> #include <fennec/langproc/strings/cstring.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h> #include <fennec/lang/typed.h>
#include <fennec/platform/interface/fwd.h> #include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/window.h>
/* /*
* This class should resemble the target platform as a whole. By itself, it will represent the OS, i.e. Linux, Windows, * This class should resemble the target platform as a whole. By itself, it will represent the OS, i.e. Linux, Windows,
@@ -64,9 +66,52 @@ public:
using shared_object = struct shared_object; using shared_object = struct shared_object;
using symbol = void*; using symbol = void*;
template<typename ctor>
struct driver {
int priority;
ctor constructor;
driver()
: priority(0)
, constructor(nullptr) {
}
driver(int priority, ctor constructor)
: priority(priority)
, constructor(constructor) {
}
driver(const driver& d)
: priority(d.priority)
, constructor(d.constructor) {
}
driver(driver&& d) noexcept
: priority(d.priority)
, constructor(d.constructor) {
}
driver& operator=(const driver& d) {
priority = d.priority;
constructor = d.constructor;
return *this;
}
driver& operator=(driver&& d) noexcept {
priority = fennec::move(d.priority);
constructor = fennec::move(d.constructor);
return *this;
}
bool operator<(const driver& d) const {
return priority > d.priority;
}
};
const string name; const string name;
virtual ~platform() = default; virtual ~platform() = default;
platform(const platform&) = delete;
// Dynamically linked objects // Dynamically linked objects
virtual shared_object* load_object(const cstring& file) = 0; virtual shared_object* load_object(const cstring& file) = 0;
@@ -76,64 +121,40 @@ public:
virtual void initialize(); // Initialize Drivers and Contexts virtual void initialize(); // Initialize Drivers and Contexts
virtual void shutdown(); // Close Drivers and Contexts virtual void shutdown(); // Close Drivers and Contexts
display* get_display() { return _display; } // Platform level functions for retrieving driver and protocol contexts ================================================
// Window Management
using window_ctor = window* (*)(platform*, const window::config&);
using window_driver = driver<window_ctor>;
window* create_window(const window::config& config);
static void register_window_driver(window_driver&& driver);
protected: protected:
template<typename PlatformT> template<typename PlatformT>
explicit platform(const cstring& name, PlatformT* type) explicit platform(const cstring& name, PlatformT* type)
: typed(type) : typed(type)
, name(name) { , name(name) {
auto& globals = _get_globals(); assertf(globals.singleton == nullptr, "Conflicting platform implementations!");
assertf(globals.singleton == nullptr, "Conflicting Platform Definitions.");
globals.singleton = this; globals.singleton = this;
} }
virtual void load_display();
display* _display;
private:
platform(const platform&) = delete;
// Static Stuff ======================================================================================================== // Static Stuff ========================================================================================================
public: public:
using display_ctor = display* (*)(platform*); static platform* instance() {
using input_ctor = inputdevice* (*)(display*); return globals.singleton;
using gfxctx_ctor = gfxcontext* (*)(display*); }
template<typename ctor>
struct driver {
int priority;
ctor constructor;
};
struct global_context {
platform* singleton;
list<driver<display_ctor>> displays;
list<driver<input_ctor>> inputs;
list<driver<gfxctx_ctor>> graphics;
global_context()
: singleton(nullptr) {
}
};
static void add_driver(display_ctor ctor, int priority);
static void add_driver(input_ctor ctor, int priority);
static void add_driver(gfxctx_ctor ctor, int priority);
private: private:
static global_context& _get_globals(); inline static struct global {
platform* singleton;
sequence<window_driver> windows;
public: global()
static const global_context& get_globals() { : singleton(nullptr)
return _get_globals(); , windows() {
} }
} globals = global();
static platform* instance() {
return _get_globals().singleton;
}
}; };
} }

View File

@@ -16,154 +16,139 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
///
/// \file window.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_WINDOW_H #ifndef FENNEC_PLATFORM_INTERFACE_WINDOW_H
#define FENNEC_PLATFORM_INTERFACE_WINDOW_H #define FENNEC_PLATFORM_INTERFACE_WINDOW_H
#include <fennec/containers/optional.h> #include <fennec/lang/types.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/platform/interface/fwd.h> #include <fennec/renderers/interface/gfxcontext.h>
#include <fennec/platform/linux/wayland/display.h>
namespace fennec namespace fennec
{ {
/// class window {
/// \brief interface for handling windows
/// \details the interface makes no guarantees about the bit-depth and is completely dependent on the implementation.
class window : public typed<window> {
public: public:
enum class fullscreen_mode { virtual ~window() = default;
windowed = 0,
borderless, enum flags : uint8_t {
fullscreen fullscreen = 0x1 << 0,
borderless = 0x1 << 1,
resizeable = 0x1 << 2,
modal = 0x1 << 3, // Treat as modal, blocks interaction with parent windows
popup = 0x1 << 4, // Treat as a popup menu
tooltip = 0x1 << 5, // Treat as a tooltip, does not receive mouse or keyboard focus
utility = 0x1 << 6, // Treat as utility, does not show in taskbar
}; };
enum flags_ : uint32_t { enum vsync {
flags_none = 0, vsync_off = 0,
flags_child = 0x1 << 0, vsync_on = 1,
flags_modal = 0x1 << 1, adaptive_sync = -1,
flags_grab_mouse = 0x1 << 2, };
flags_grab_keyboard = 0x1 << 3,
flags_block_screensaver = 0x1 << 4, struct pixel_format {
uint8_t r, g, b, a;
bool floating_point;
};
struct display_mode {
pixel_format format;
float rate;
float density;
}; };
struct config { struct config {
string title; uint8_t flags;
uint32_t flags; display_mode mode;
size_t width, height; string title;
fullscreen_mode fullscreen; int8_t vsync;
}; };
virtual ~window() = default; // Properties ==========================================================================================================
virtual bool running() = 0; virtual bool running() = 0;
virtual void configure(const config& config) = 0;
virtual bool initialize(bool modal) = 0;
virtual bool shutdown() = 0;
virtual bool set_title(const cstring& title) = 0; bool is_fullscreen() const {
virtual bool set_title(const string& title) = 0; return _config.flags & fullscreen;
}
virtual bool set_width(size_t w) = 0; bool is_borderless() const {
virtual bool set_height(size_t h) = 0; return _config.flags & borderless;
virtual bool resize(size_t w, size_t h) = 0;
virtual bool set_fullscreen_mode(fullscreen_mode mode) = 0;
virtual bool set_resizable(bool e) = 0;
virtual bool grab_keyboard(bool e) = 0;
virtual bool grab_mouse(bool e) = 0;
virtual bool block_screensaver(bool e) = 0;
virtual struct wl_surface* get_native_handle() = 0;
bool is_child() const {
if (not _config) return false;
return _config->flags & flags_child;
} }
bool is_modal() const { bool is_modal() const {
if (not _config) return false; return _config.flags & modal;
return _config->flags & flags_modal;
} }
display* get_display() { bool is_resizeable() const {
return _display; return _config.flags & resizeable;
} }
const display* get_display() const { const display_mode& get_mode() const {
return _display; return _config.mode;
}
const pixel_format& get_format() const {
return _config.mode.format;
}
bool is_hdr() const {
static constexpr size_t sdr = 255ull * 255ull * 255ull;
const pixel_format& fmt = _config.mode.format;
return fmt.r * fmt.g * fmt.b > sdr;
} }
const config& get_config() const { const config& get_config() const {
return *_config; return _config;
} }
// Modifiers ===========================================================================================================
const string& get_title() const { virtual void resize(size_t, size_t) = 0;
static const string _null{"null"}; virtual void position(size_t, size_t) = 0;
if (not _config) return _null;
return _config->title;
}
virtual void set_fullscreen(bool) = 0;
virtual void set_borderless(bool) = 0;
size_t get_width() const { virtual void grab_mouse(bool) = 0;
if (not _config) return false; virtual void grab_keyboard(bool) = 0;
return _config->width;
}
size_t get_height() const { virtual void set_title(const cstring&) = 0;
if (not _config) return false; virtual void set_title(const string&) = 0;
return _config->height; virtual void set_progress(bool, float) = 0;
}
virtual void vsync(int8_t) = 0;
fullscreen_mode get_fullscreen_mode() const { // Graphics ============================================================================================================
if (not _config) return fullscreen_mode::windowed;
return _config->fullscreen;
}
virtual void begin_frame() = 0;
bool is_keyboard_grabbed() const { virtual void end_frame() = 0;
if (not _config) return false;
return _config->flags & flags_grab_keyboard;
}
bool is_mouse_grabbed() const {
if (not _config) return false;
return _config->flags & flags_grab_mouse;
}
bool is_screensaver_blocked() const {
if (not _config) return false;
return _config->flags & flags_block_screensaver;
}
template<class DisplayT>
DisplayT* get_display() {
return static_cast<DisplayT*>(_display);
}
protected: protected:
template<typename TypeT> window* _parent;
window(display* display, window* parent, TypeT* type) gfxcontext* _context;
: typed(type) config _config;
, _display(display)
, _parent(parent) window(window* parent, const config& cfg)
, _surface(nullptr) { : _parent(parent)
, _config(cfg) {
} }
display* _display;
window* _parent;
optional<config> _config;
gfxsurface* _surface;
private:
private: private:
}; };
} }
#endif // FENNEC_PLATFORM_INTERFACE_WINDOW_H #endif // FENNEC_PLATFORM_INTERFACE_WINDOW_H

View File

@@ -1,71 +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/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H
#include <fennec/platform/interface/display.h>
#include <fennec/platform/linux/wayland/lib/wayland.h>
namespace fennec
{
class wayland_display : public display {
public:
explicit wayland_display(platform* platform);
~wayland_display() override;
bool connected() const override;
void* get_native_handle() override { return _handle; }
window* create_window(window* parent) override;
wl_registry* get_registry() { return _registry; }
const wl_registry* get_registry() const { return _registry; }
wl_compositor* get_compositor() { return _compositor; }
const wl_compositor* get_compositor() const { return _compositor; }
// xdg_wm_base* get_shell() { return _shell; }
//const xdg_wm_base* get_shell() const { return _shell; }
wl_seat* get_seat() { return _seat; }
const wl_seat* get_seat() const { return _seat; }
wl_shm* get_shm() { return _shm; }
const wl_shm* get_shm() const { return _shm; }
private:
wl_display* _handle;
wl_registry* _registry;
wl_compositor* _compositor;
//xdg_wm_base* _shell;
wl_seat* _seat;
wl_shm* _shm;
bool _fifo;
void cleanup();
static void listen_global(void*, wl_registry*, uint32_t, const char*, uint32_t);
static void listen_global_remove(void*, wl_registry*, uint32_t);
static void listen_seat(void*, wl_seat*, uint32_t);
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_DISPLAY_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,526 +0,0 @@
/* Generated by wayland-scanner 1.23.1 */
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2010-2011 Intel Corporation
* Copyright © 2012-2013 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_buffer_interface;
extern const struct wl_interface wl_callback_interface;
extern const struct wl_interface wl_data_device_interface;
extern const struct wl_interface wl_data_offer_interface;
extern const struct wl_interface wl_data_source_interface;
extern const struct wl_interface wl_keyboard_interface;
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_pointer_interface;
extern const struct wl_interface wl_region_interface;
extern const struct wl_interface wl_registry_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_shell_surface_interface;
extern const struct wl_interface wl_shm_pool_interface;
extern const struct wl_interface wl_subsurface_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface wl_touch_interface;
static const struct wl_interface *wayland_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_callback_interface,
&wl_registry_interface,
&wl_surface_interface,
&wl_region_interface,
&wl_buffer_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_shm_pool_interface,
NULL,
NULL,
&wl_data_source_interface,
&wl_surface_interface,
&wl_surface_interface,
NULL,
&wl_data_source_interface,
NULL,
&wl_data_offer_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_data_offer_interface,
&wl_data_offer_interface,
&wl_data_source_interface,
&wl_data_device_interface,
&wl_seat_interface,
&wl_shell_surface_interface,
&wl_surface_interface,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_buffer_interface,
NULL,
NULL,
&wl_callback_interface,
&wl_region_interface,
&wl_region_interface,
&wl_output_interface,
&wl_output_interface,
&wl_pointer_interface,
&wl_keyboard_interface,
&wl_touch_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_subsurface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
};
static const struct wl_message wl_display_requests[] = {
{ "sync", "n", wayland_types + 8 },
{ "get_registry", "n", wayland_types + 9 },
};
static const struct wl_message wl_display_events[] = {
{ "error", "ous", wayland_types + 0 },
{ "delete_id", "u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_display_interface = {
"wl_display", 1,
2, wl_display_requests,
2, wl_display_events,
};
static const struct wl_message wl_registry_requests[] = {
{ "bind", "usun", wayland_types + 0 },
};
static const struct wl_message wl_registry_events[] = {
{ "global", "usu", wayland_types + 0 },
{ "global_remove", "u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_registry_interface = {
"wl_registry", 1,
1, wl_registry_requests,
2, wl_registry_events,
};
static const struct wl_message wl_callback_events[] = {
{ "done", "u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_callback_interface = {
"wl_callback", 1,
0, NULL,
1, wl_callback_events,
};
static const struct wl_message wl_compositor_requests[] = {
{ "create_surface", "n", wayland_types + 10 },
{ "create_region", "n", wayland_types + 11 },
};
WL_PRIVATE const struct wl_interface wl_compositor_interface = {
"wl_compositor", 6,
2, wl_compositor_requests,
0, NULL,
};
static const struct wl_message wl_shm_pool_requests[] = {
{ "create_buffer", "niiiiu", wayland_types + 12 },
{ "destroy", "", wayland_types + 0 },
{ "resize", "i", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_shm_pool_interface = {
"wl_shm_pool", 2,
3, wl_shm_pool_requests,
0, NULL,
};
static const struct wl_message wl_shm_requests[] = {
{ "create_pool", "nhi", wayland_types + 18 },
{ "release", "2", wayland_types + 0 },
};
static const struct wl_message wl_shm_events[] = {
{ "format", "u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_shm_interface = {
"wl_shm", 2,
2, wl_shm_requests,
1, wl_shm_events,
};
static const struct wl_message wl_buffer_requests[] = {
{ "destroy", "", wayland_types + 0 },
};
static const struct wl_message wl_buffer_events[] = {
{ "release", "", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_buffer_interface = {
"wl_buffer", 1,
1, wl_buffer_requests,
1, wl_buffer_events,
};
static const struct wl_message wl_data_offer_requests[] = {
{ "accept", "u?s", wayland_types + 0 },
{ "receive", "sh", wayland_types + 0 },
{ "destroy", "", wayland_types + 0 },
{ "finish", "3", wayland_types + 0 },
{ "set_actions", "3uu", wayland_types + 0 },
};
static const struct wl_message wl_data_offer_events[] = {
{ "offer", "s", wayland_types + 0 },
{ "source_actions", "3u", wayland_types + 0 },
{ "action", "3u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_data_offer_interface = {
"wl_data_offer", 3,
5, wl_data_offer_requests,
3, wl_data_offer_events,
};
static const struct wl_message wl_data_source_requests[] = {
{ "offer", "s", wayland_types + 0 },
{ "destroy", "", wayland_types + 0 },
{ "set_actions", "3u", wayland_types + 0 },
};
static const struct wl_message wl_data_source_events[] = {
{ "target", "?s", wayland_types + 0 },
{ "send", "sh", wayland_types + 0 },
{ "cancelled", "", wayland_types + 0 },
{ "dnd_drop_performed", "3", wayland_types + 0 },
{ "dnd_finished", "3", wayland_types + 0 },
{ "action", "3u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_data_source_interface = {
"wl_data_source", 3,
3, wl_data_source_requests,
6, wl_data_source_events,
};
static const struct wl_message wl_data_device_requests[] = {
{ "start_drag", "?oo?ou", wayland_types + 21 },
{ "set_selection", "?ou", wayland_types + 25 },
{ "release", "2", wayland_types + 0 },
};
static const struct wl_message wl_data_device_events[] = {
{ "data_offer", "n", wayland_types + 27 },
{ "enter", "uoff?o", wayland_types + 28 },
{ "leave", "", wayland_types + 0 },
{ "motion", "uff", wayland_types + 0 },
{ "drop", "", wayland_types + 0 },
{ "selection", "?o", wayland_types + 33 },
};
WL_PRIVATE const struct wl_interface wl_data_device_interface = {
"wl_data_device", 3,
3, wl_data_device_requests,
6, wl_data_device_events,
};
static const struct wl_message wl_data_device_manager_requests[] = {
{ "create_data_source", "n", wayland_types + 34 },
{ "get_data_device", "no", wayland_types + 35 },
};
WL_PRIVATE const struct wl_interface wl_data_device_manager_interface = {
"wl_data_device_manager", 3,
2, wl_data_device_manager_requests,
0, NULL,
};
static const struct wl_message wl_shell_requests[] = {
{ "get_shell_surface", "no", wayland_types + 37 },
};
WL_PRIVATE const struct wl_interface wl_shell_interface = {
"wl_shell", 1,
1, wl_shell_requests,
0, NULL,
};
static const struct wl_message wl_shell_surface_requests[] = {
{ "pong", "u", wayland_types + 0 },
{ "move", "ou", wayland_types + 39 },
{ "resize", "ouu", wayland_types + 41 },
{ "set_toplevel", "", wayland_types + 0 },
{ "set_transient", "oiiu", wayland_types + 44 },
{ "set_fullscreen", "uu?o", wayland_types + 48 },
{ "set_popup", "ouoiiu", wayland_types + 51 },
{ "set_maximized", "?o", wayland_types + 57 },
{ "set_title", "s", wayland_types + 0 },
{ "set_class", "s", wayland_types + 0 },
};
static const struct wl_message wl_shell_surface_events[] = {
{ "ping", "u", wayland_types + 0 },
{ "configure", "uii", wayland_types + 0 },
{ "popup_done", "", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_shell_surface_interface = {
"wl_shell_surface", 1,
10, wl_shell_surface_requests,
3, wl_shell_surface_events,
};
static const struct wl_message wl_surface_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "attach", "?oii", wayland_types + 58 },
{ "damage", "iiii", wayland_types + 0 },
{ "frame", "n", wayland_types + 61 },
{ "set_opaque_region", "?o", wayland_types + 62 },
{ "set_input_region", "?o", wayland_types + 63 },
{ "commit", "", wayland_types + 0 },
{ "set_buffer_transform", "2i", wayland_types + 0 },
{ "set_buffer_scale", "3i", wayland_types + 0 },
{ "damage_buffer", "4iiii", wayland_types + 0 },
{ "offset", "5ii", wayland_types + 0 },
};
static const struct wl_message wl_surface_events[] = {
{ "enter", "o", wayland_types + 64 },
{ "leave", "o", wayland_types + 65 },
{ "preferred_buffer_scale", "6i", wayland_types + 0 },
{ "preferred_buffer_transform", "6u", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_surface_interface = {
"wl_surface", 6,
11, wl_surface_requests,
4, wl_surface_events,
};
static const struct wl_message wl_seat_requests[] = {
{ "get_pointer", "n", wayland_types + 66 },
{ "get_keyboard", "n", wayland_types + 67 },
{ "get_touch", "n", wayland_types + 68 },
{ "release", "5", wayland_types + 0 },
};
static const struct wl_message wl_seat_events[] = {
{ "capabilities", "u", wayland_types + 0 },
{ "name", "2s", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_seat_interface = {
"wl_seat", 9,
4, wl_seat_requests,
2, wl_seat_events,
};
static const struct wl_message wl_pointer_requests[] = {
{ "set_cursor", "u?oii", wayland_types + 69 },
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_pointer_events[] = {
{ "enter", "uoff", wayland_types + 73 },
{ "leave", "uo", wayland_types + 77 },
{ "motion", "uff", wayland_types + 0 },
{ "button", "uuuu", wayland_types + 0 },
{ "axis", "uuf", wayland_types + 0 },
{ "frame", "5", wayland_types + 0 },
{ "axis_source", "5u", wayland_types + 0 },
{ "axis_stop", "5uu", wayland_types + 0 },
{ "axis_discrete", "5ui", wayland_types + 0 },
{ "axis_value120", "8ui", wayland_types + 0 },
{ "axis_relative_direction", "9uu", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_pointer_interface = {
"wl_pointer", 9,
2, wl_pointer_requests,
11, wl_pointer_events,
};
static const struct wl_message wl_keyboard_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_keyboard_events[] = {
{ "keymap", "uhu", wayland_types + 0 },
{ "enter", "uoa", wayland_types + 79 },
{ "leave", "uo", wayland_types + 82 },
{ "key", "uuuu", wayland_types + 0 },
{ "modifiers", "uuuuu", wayland_types + 0 },
{ "repeat_info", "4ii", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_keyboard_interface = {
"wl_keyboard", 9,
1, wl_keyboard_requests,
6, wl_keyboard_events,
};
static const struct wl_message wl_touch_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_touch_events[] = {
{ "down", "uuoiff", wayland_types + 84 },
{ "up", "uui", wayland_types + 0 },
{ "motion", "uiff", wayland_types + 0 },
{ "frame", "", wayland_types + 0 },
{ "cancel", "", wayland_types + 0 },
{ "shape", "6iff", wayland_types + 0 },
{ "orientation", "6if", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_touch_interface = {
"wl_touch", 9,
1, wl_touch_requests,
7, wl_touch_events,
};
static const struct wl_message wl_output_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_output_events[] = {
{ "geometry", "iiiiissi", wayland_types + 0 },
{ "mode", "uiii", wayland_types + 0 },
{ "done", "2", wayland_types + 0 },
{ "scale", "2i", wayland_types + 0 },
{ "name", "4s", wayland_types + 0 },
{ "description", "4s", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_output_interface = {
"wl_output", 4,
1, wl_output_requests,
6, wl_output_events,
};
static const struct wl_message wl_region_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "add", "iiii", wayland_types + 0 },
{ "subtract", "iiii", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_region_interface = {
"wl_region", 1,
3, wl_region_requests,
0, NULL,
};
static const struct wl_message wl_subcompositor_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "get_subsurface", "noo", wayland_types + 90 },
};
WL_PRIVATE const struct wl_interface wl_subcompositor_interface = {
"wl_subcompositor", 1,
2, wl_subcompositor_requests,
0, NULL,
};
static const struct wl_message wl_subsurface_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "set_position", "ii", wayland_types + 0 },
{ "place_above", "o", wayland_types + 93 },
{ "place_below", "o", wayland_types + 94 },
{ "set_sync", "", wayland_types + 0 },
{ "set_desync", "", wayland_types + 0 },
};
WL_PRIVATE const struct wl_interface wl_subsurface_interface = {
"wl_subsurface", 1,
6, wl_subsurface_requests,
0, NULL,
};

View File

@@ -1,184 +0,0 @@
/* Generated by wayland-scanner 1.23.1 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 6,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 6,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 6,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 6,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 6,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View File

@@ -1,114 +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/>.
// =====================================================================================================================
#include <fennec/lang/types.h>
#ifndef FENNEC_LIB
#define FENNEC_LIB(...)
#endif
#ifndef FENNEC_SYMBOL
#define FENNEC_SYMBOL(...)
#endif
#ifndef FENNEC_GLOBAL
#define FENNEC_GLOBAL(...)
#endif
FENNEC_LIB(WAYLAND);
FENNEC_SYMBOL(void, wl_proxy_marshal, struct wl_proxy*, uint32_t, ...);
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_flags, struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, uint32_t, ...);
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_create, struct wl_proxy*, const struct wl_interface*);
FENNEC_SYMBOL(void, wl_proxy_destroy, struct wl_proxy*);
FENNEC_SYMBOL(int, wl_proxy_add_listener, struct wl_proxy*, void (**)(void), void*);
FENNEC_SYMBOL(void, wl_proxy_set_user_data, struct wl_proxy*, void*);
FENNEC_SYMBOL(void*, wl_proxy_get_user_data, struct wl_proxy*);
FENNEC_SYMBOL(uint32_t, wl_proxy_get_version, struct wl_proxy*);
FENNEC_SYMBOL(uint32_t, wl_proxy_get_id, struct wl_proxy*);
FENNEC_SYMBOL(const char*, wl_proxy_get_class, struct wl_proxy*);
FENNEC_SYMBOL(void, wl_proxy_set_queue, struct wl_proxy*, struct wl_event_queue*);
FENNEC_SYMBOL(void*, wl_proxy_create_wrapper, void*);
FENNEC_SYMBOL(void, wl_proxy_wrapper_destroy, void*);
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor, struct wl_proxy*, uint32_t, const struct wl_interface*, ...);
FENNEC_SYMBOL(struct wl_proxy*, wl_proxy_marshal_constructor_versioned, struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, ...);
FENNEC_SYMBOL(void, wl_proxy_set_tag, struct wl_proxy*, const char* const*);
FENNEC_SYMBOL(const char* const*, wl_proxy_get_tag, struct wl_proxy*);
FENNEC_SYMBOL(struct wl_display*, wl_display_connect, const char*);
FENNEC_SYMBOL(struct wl_display*, wl_display_connect_to_fd, int);
FENNEC_SYMBOL(void, wl_display_disconnect, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_get_fd, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_dispatch, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_dispatch_queue, struct wl_display*, struct wl_event_queue*);
FENNEC_SYMBOL(int, wl_display_dispatch_queue_pending, struct wl_display*, struct wl_event_queue*);
FENNEC_SYMBOL(int, wl_display_dispatch_pending, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_prepare_read, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_prepare_read_queue, struct wl_display*, struct wl_event_queue*);
FENNEC_SYMBOL(int, wl_display_read_events, struct wl_display*);
FENNEC_SYMBOL(void, wl_display_cancel_read, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_get_error, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_flush, struct wl_display*);
FENNEC_SYMBOL(int, wl_display_roundtrip, struct wl_display*);
FENNEC_SYMBOL(struct wl_event_queue*, wl_display_create_queue, struct wl_display*);
FENNEC_SYMBOL(void, wl_event_queue_destroy, struct wl_event_queue*);
FENNEC_SYMBOL(void, wl_log_set_handler_client, wl_log_func_t);
FENNEC_SYMBOL(void, wl_list_init, struct wl_list*);
FENNEC_SYMBOL(void, wl_list_insert, struct wl_list*, struct wl_list*) ;
FENNEC_SYMBOL(void, wl_list_remove, struct wl_list*);
FENNEC_SYMBOL(int, wl_list_length, const struct wl_list*);
FENNEC_SYMBOL(int, wl_list_empty, const struct wl_list*);
FENNEC_SYMBOL(void, wl_list_insert_list, struct wl_list*, struct wl_list*);
FENNEC_GLOBAL(const struct wl_interface, wl_display_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_registry_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_callback_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_compositor_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_shm_pool_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_shm_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_buffer_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_data_offer_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_data_source_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_data_device_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_data_device_manager_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_shell_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_shell_surface_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_surface_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_seat_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_pointer_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_keyboard_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_touch_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_output_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_region_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_subcompositor_interface);
FENNEC_GLOBAL(const struct wl_interface, wl_subsurface_interface);
FENNEC_LIB(WAYLAND_EGL);
FENNEC_SYMBOL(struct wl_egl_window*, wl_egl_window_create, struct wl_surface *surface, int width, int height);
FENNEC_SYMBOL(void, wl_egl_window_destroy, struct wl_egl_window *egl_window);
FENNEC_SYMBOL(void, wl_egl_window_resize, struct wl_egl_window *egl_window, int width, int height, int dx, int dy);
FENNEC_SYMBOL(void, wl_egl_window_get_attached_size, struct wl_egl_window *egl_window, int *width, int *height);
#undef FENNEC_LIB
#undef FENNEC_SYMBOL
#undef FENNEC_GLOBAL

View File

@@ -1,98 +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/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H
#include <wayland-client-core.h>
#define FENNEC_LIB(name) extern "C" bool FENNEC_HAS_LIB_##name;
#define FENNEC_SYMBOL(ret, fn, ...) using WAYLAND_sym_##fn = ret(*)(__VA_ARGS__); \
extern "C" WAYLAND_sym_##fn WAYLAND_##fn;
#define FENNEC_GLOBAL(type, name) extern "C" type* WAYLAND_##name;
#include <fennec/platform/linux/wayland/lib/sym.h>
#define wl_proxy_marshal WAYLAND_wl_proxy_marshal
#define wl_proxy_marshal_flags WAYLAND_wl_proxy_marshal_flags
#define wl_proxy_create WAYLAND_wl_proxy_create
#define wl_proxy_destroy WAYLAND_wl_proxy_destroy
#define wl_proxy_add_listener WAYLAND_wl_proxy_add_listener
#define wl_proxy_set_user_data WAYLAND_wl_proxy_set_user_data
#define wl_proxy_get_user_data WAYLAND_wl_proxy_get_user_data
#define wl_proxy_get_version WAYLAND_wl_proxy_get_version
#define wl_proxy_get_id WAYLAND_wl_proxy_get_id
#define wl_proxy_get_class WAYLAND_wl_proxy_get_class
#define wl_proxy_set_queue WAYLAND_wl_proxy_set_queue
#define wl_proxy_create_wrapper WAYLAND_wl_proxy_create_wrapper
#define wl_proxy_wrapper_destroy WAYLAND_wl_proxy_wrapper_destroy
#define wl_proxy_marshal_constructor WAYLAND_wl_proxy_marshal_constructor
#define wl_proxy_marshal_constructor_versioned WAYLAND_wl_proxy_marshal_constructor_versioned
#define wl_proxy_set_tag WAYLAND_wl_proxy_set_tag
#define wl_proxy_get_tag WAYLAND_wl_proxy_get_tag
#define wl_event_queue_destroy WAYLAND_wl_event_queue_destroy
#define wl_log_set_handler_client WAYLAND_wl_log_set_handler_client
#define wl_list_init WAYLAND_wl_list_init
#define wl_list_insert WAYLAND_wl_list_insert
#define wl_list_remove WAYLAND_wl_list_remove
#define wl_list_length WAYLAND_wl_list_length
#define wl_list_empty WAYLAND_wl_list_empty
#define wl_list_insert_list WAYLAND_wl_list_insert_list
#define wl_display_connect WAYLAND_wl_display_connect
#define wl_display_connect_to_fd WAYLAND_wl_display_connect_to_fd
#define wl_display_reconnect WAYLAND_wl_display_reconnect
#define wl_display_disconnect WAYLAND_wl_display_disconnect
#define wl_display_get_fd WAYLAND_wl_display_get_fd
#define wl_display_dispatch WAYLAND_wl_display_dispatch
#define wl_display_dispatch_queue WAYLAND_wl_display_dispatch_queue
#define wl_display_dispatch_queue_pending WAYLAND_wl_display_dispatch_queue_pending
#define wl_display_dispatch_pending WAYLAND_wl_display_dispatch_pending
#define wl_display_prepare_read WAYLAND_wl_display_prepare_read
#define wl_display_prepare_read_queue WAYLAND_wl_display_prepare_read_queue
#define wl_display_read_events WAYLAND_wl_display_read_events
#define wl_display_cancel_read WAYLAND_wl_display_cancel_read
#define wl_display_get_error WAYLAND_wl_display_get_error
#define wl_display_flush WAYLAND_wl_display_flush
#define wl_display_roundtrip WAYLAND_wl_display_roundtrip
#define wl_display_create_queue WAYLAND_wl_display_create_queue
#define wl_seat_interface *WAYLAND_wl_seat_interface
#define wl_surface_interface *WAYLAND_wl_surface_interface
#define wl_shm_pool_interface *WAYLAND_wl_shm_pool_interface
#define wl_buffer_interface *WAYLAND_wl_buffer_interface
#define wl_registry_interface *WAYLAND_wl_registry_interface
#define wl_region_interface *WAYLAND_wl_region_interface
#define wl_pointer_interface *WAYLAND_wl_pointer_interface
#define wl_keyboard_interface *WAYLAND_wl_keyboard_interface
#define wl_compositor_interface *WAYLAND_wl_compositor_interface
#define wl_output_interface *WAYLAND_wl_output_interface
#define wl_shm_interface *WAYLAND_wl_shm_interface
#define wl_data_device_interface *WAYLAND_wl_data_device_interface
#define wl_data_offer_interface *WAYLAND_wl_data_offer_interface
#define wl_data_source_interface *WAYLAND_wl_data_source_interface
#define wl_data_device_manager_interface *WAYLAND_wl_data_device_manager_interface
#define wl_egl_window_create WAYLAND_wl_egl_window_create
#define wl_egl_window_destroy WAYLAND_wl_egl_window_destroy
#define wl_egl_window_resize WAYLAND_wl_egl_window_resize
#define wl_egl_window_get_attached_size WAYLAND_wl_egl_window_get_attached_size
#include <fennec/platform/linux/wayland/lib/headers/wayland-client-protocols.h>
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIB_WAYLAND_CLIENT_H

View File

@@ -1,83 +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 window.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_LINUX_WAYLAND_WINDOW_H
#define FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H
#include <fennec/platform/interface/window.h>
#include <fennec/platform/linux/wayland/display.h>
namespace fennec
{
class wayland_window : public window {
public:
bool running() override;
void configure(const config& config) override;
bool initialize(bool modal) override;
bool shutdown() override;
bool set_title(const cstring& title) override;
bool set_title(const string& title) override;
bool set_width(size_t w) override;
bool set_height(size_t h) override;
bool resize(size_t w, size_t h) override;
bool set_resizable(bool e) override;
bool set_fullscreen_mode(fullscreen_mode mode) override;
bool grab_keyboard(bool e) override;
bool grab_mouse(bool e) override;
bool block_screensaver(bool e) override;
wayland_window(wayland_display* display, wayland_window* parent);
~wayland_window() override;
struct wl_surface* get_native_handle() override {
return _handle;
}
private:
wl_surface* _handle;
wl_shell_surface* _shell;
size_t _nfs_width, _nfs_height;
static void listen_ping(void*, wl_shell_surface*, uint32_t);
static void listen_configure(void*, wl_shell_surface*, uint32_t, int32_t, int32_t);
static void listen_popup_done(void*, wl_shell_surface*);
};
}
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_WINDOW_H

View File

@@ -1,144 +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/>.
// =====================================================================================================================
/*
* Copyright © 2009-2012 Daniel Stone
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include <stdio.h>
#ifndef FENNEC_LIB
#define FENNEC_LIB(...)
#endif
#ifndef FENNEC_SYMBOL
#define FENNEC_SYMBOL(...)
#endif
#ifndef FENNEC_GLOBAL
#define FENNEC_GLOBAL(...)
#endif
FENNEC_LIB(XKB);
FENNEC_SYMBOL(int, xkb_keysym_get_name, xkb_keysym_t, char*, size_t);
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_from_name, const char*, enum xkb_keysym_flags);
FENNEC_SYMBOL(int, xkb_keysym_to_utf8, xkb_keysym_t, char*, size_t);
FENNEC_SYMBOL(uint32_t, xkb_keysym_to_utf32, xkb_keysym_t);
FENNEC_SYMBOL(xkb_keysym_t, xkb_utf32_to_keysym, uint32_t);
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_upper, xkb_keysym_t);
FENNEC_SYMBOL(xkb_keysym_t, xkb_keysym_to_lower, xkb_keysym_t);
FENNEC_SYMBOL(struct xkb_context*, xkb_context_new, enum xkb_context_flags);
FENNEC_SYMBOL(struct xkb_context*, xkb_context_ref, struct xkb_context*);
FENNEC_SYMBOL(void, xkb_context_unref, struct xkb_context*);
FENNEC_SYMBOL(void, xkb_context_set_user_data, struct xkb_context*, void*);
FENNEC_SYMBOL(void*, xkb_context_get_user_data, struct xkb_context*);
FENNEC_SYMBOL(int, xkb_context_include_path_append, struct xkb_context*, const char*);
FENNEC_SYMBOL(int, xkb_context_include_path_append_default, struct xkb_context*);
FENNEC_SYMBOL(int, xkb_context_include_path_reset_defaults, struct xkb_context*);
FENNEC_SYMBOL(void, xkb_context_include_path_clear, struct xkb_context*);
FENNEC_SYMBOL(unsigned int, xkb_context_num_include_paths, struct xkb_context*);
FENNEC_SYMBOL(const char*, xkb_context_include_path_get, struct xkb_context*, unsigned int);
FENNEC_SYMBOL(void, xkb_context_set_log_level, struct xkb_context*, enum xkb_log_level);
FENNEC_SYMBOL(enum xkb_log_level, xkb_context_get_log_level, struct xkb_context*);
FENNEC_SYMBOL(void, xkb_context_set_log_verbosity, struct xkb_context*, int);
FENNEC_SYMBOL(int, xkb_context_get_log_verbosity, struct xkb_context*);
FENNEC_SYMBOL(void, xkb_context_set_log_fn, struct xkb_context*, void (*)(struct xkb_context*, enum xkb_log_level, const char*, va_list));
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_names, struct xkb_context*, const struct xkb_rule_names*, enum xkb_keymap_compile_flags);
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_file, struct xkb_context*, FILE*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_string, struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_new_from_buffer, struct xkb_context*, const char*, size_t, enum xkb_keymap_format, enum xkb_keymap_compile_flags);
FENNEC_SYMBOL(struct xkb_keymap*, xkb_keymap_ref, struct xkb_keymap*);
FENNEC_SYMBOL(void, xkb_keymap_unref, struct xkb_keymap*);
FENNEC_SYMBOL(char*, xkb_keymap_get_as_string, struct xkb_keymap*, enum xkb_keymap_format);
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_min_keycode, struct xkb_keymap*);
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_max_keycode, struct xkb_keymap*);
FENNEC_SYMBOL(void, xkb_keymap_key_for_each, struct xkb_keymap*, xkb_keymap_key_iter_t, void*);
FENNEC_SYMBOL(const char*, xkb_keymap_key_get_name, struct xkb_keymap*, xkb_keycode_t);
FENNEC_SYMBOL(xkb_keycode_t, xkb_keymap_key_by_name, struct xkb_keymap*, const char*);
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_num_mods, struct xkb_keymap*);
FENNEC_SYMBOL(const char*, xkb_keymap_mod_get_name, struct xkb_keymap*, xkb_mod_index_t);
FENNEC_SYMBOL(xkb_mod_index_t, xkb_keymap_mod_get_index, struct xkb_keymap*, const char*);
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts, struct xkb_keymap*);
FENNEC_SYMBOL(const char*, xkb_keymap_layout_get_name, struct xkb_keymap*, xkb_layout_index_t);
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_layout_get_index, struct xkb_keymap*, const char*);
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_num_leds, struct xkb_keymap*);
FENNEC_SYMBOL(const char*, xkb_keymap_led_get_name, struct xkb_keymap*, xkb_led_index_t);
FENNEC_SYMBOL(xkb_led_index_t, xkb_keymap_led_get_index, struct xkb_keymap*, const char*);
FENNEC_SYMBOL(xkb_layout_index_t, xkb_keymap_num_layouts_for_key, struct xkb_keymap*, xkb_keycode_t);
FENNEC_SYMBOL(xkb_level_index_t, xkb_keymap_num_levels_for_key, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t);
FENNEC_SYMBOL(size_t, xkb_keymap_key_get_mods_for_level, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, xkb_mod_mask_t*, size_t);
FENNEC_SYMBOL(int, xkb_keymap_key_get_syms_by_level, struct xkb_keymap*, xkb_keycode_t, xkb_layout_index_t, xkb_level_index_t, const xkb_keysym_t**);
FENNEC_SYMBOL(int, xkb_keymap_key_repeats, struct xkb_keymap*, xkb_keycode_t);
FENNEC_SYMBOL(struct xkb_state*, xkb_state_new, struct xkb_keymap*);
FENNEC_SYMBOL(struct xkb_state*, xkb_state_ref, struct xkb_state*);
FENNEC_SYMBOL(void, xkb_state_unref, struct xkb_state*);
FENNEC_SYMBOL(struct xkb_keymap*, xkb_state_get_keymap, struct xkb_state*);
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_key, struct xkb_state*, xkb_keycode_t, enum xkb_key_direction);
FENNEC_SYMBOL(enum xkb_state_component, xkb_state_update_mask, struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
FENNEC_SYMBOL(int, xkb_state_key_get_syms, struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
FENNEC_SYMBOL(int, xkb_state_key_get_utf8, struct xkb_state*, xkb_keycode_t, char*, size_t);
FENNEC_SYMBOL(uint32_t, xkb_state_key_get_utf32, struct xkb_state*, xkb_keycode_t);
FENNEC_SYMBOL(xkb_keysym_t, xkb_state_key_get_one_sym, struct xkb_state*, xkb_keycode_t);
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_key_get_layout, struct xkb_state*, xkb_keycode_t);
FENNEC_SYMBOL(xkb_level_index_t, xkb_state_key_get_level, struct xkb_state*, xkb_keycode_t, xkb_layout_index_t);
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_serialize_mods, struct xkb_state*, enum xkb_state_component);
FENNEC_SYMBOL(xkb_layout_index_t, xkb_state_serialize_layout, struct xkb_state*, enum xkb_state_component);
FENNEC_SYMBOL(int, xkb_state_mod_name_is_active, struct xkb_state*, const char*, enum xkb_state_component);
FENNEC_SYMBOL(int, xkb_state_mod_names_are_active, struct xkb_state*, enum xkb_state_component, enum xkb_state_match, ...);
FENNEC_SYMBOL(int, xkb_state_mod_index_is_active, struct xkb_state*, xkb_mod_index_t, enum xkb_state_component);
FENNEC_SYMBOL(int, xkb_state_mod_indices_are_active, struct xkb_state*, enum xkb_state_component, enum xkb_state_match, ...);
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods2, struct xkb_state*, xkb_keycode_t, enum xkb_consumed_mode);
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_key_get_consumed_mods, struct xkb_state*, xkb_keycode_t);
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed2, struct xkb_state*, xkb_keycode_t, xkb_mod_index_t, enum xkb_consumed_mode);
FENNEC_SYMBOL(int, xkb_state_mod_index_is_consumed, struct xkb_state*, xkb_keycode_t, xkb_mod_index_t);
FENNEC_SYMBOL(xkb_mod_mask_t, xkb_state_mod_mask_remove_consumed, struct xkb_state*, xkb_keycode_t, xkb_mod_mask_t);
FENNEC_SYMBOL(int, xkb_state_layout_name_is_active, struct xkb_state*, const char*, enum xkb_state_component);
FENNEC_SYMBOL(int, xkb_state_layout_index_is_active, struct xkb_state*, xkb_layout_index_t, enum xkb_state_component);
FENNEC_SYMBOL(int, xkb_state_led_name_is_active, struct xkb_state*, const char*);
FENNEC_SYMBOL(int, xkb_state_led_index_is_active, struct xkb_state*, xkb_led_index_t);
#undef FENNEC_LIB
#undef FENNEC_SYMBOL
#undef FENNEC_GLOBAL

View File

@@ -1,110 +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/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_LINUX_XKB_LIB_XKB_H
#define FENNEC_PLATFORM_LINUX_XKB_LIB_XKB_H
#include <xkbcommon/xkbcommon.h>
#define FENNEC_LIB(name) extern bool FENNEC_HAS_LIB_##name;
#define FENNEC_SYMBOL(ret, fn, ...) using XKB_sym_##fn = ret(*)(__VA_ARGS__); \
extern XKB_sym_##fn XKB_##fn;
#define FENNEC_GLOBAL(type, name) extern type* XKB_##name;
#include <fennec/platform/linux/xkb/lib/sym.h>
#define xkb_keysym_get_name XKB_xkb_keysym_get_name
#define xkb_keysym_from_name XKB_xkb_keysym_from_name
#define xkb_keysym_to_utf8 XKB_xkb_keysym_to_utf8
#define xkb_keysym_to_utf32 XKB_xkb_keysym_to_utf32
#define xkb_utf32_to_keysym XKB_xkb_utf32_to_keysym
#define xkb_keysym_to_upper XKB_xkb_keysym_to_upper
#define xkb_keysym_to_lower XKB_xkb_keysym_to_lower
#define xkb_context_new XKB_xkb_context_new
#define xkb_context_ref XKB_xkb_context_ref
#define xkb_context_unref XKB_xkb_context_unref
#define xkb_context_set_user_data XKB_xkb_context_set_user_data
#define xkb_context_get_user_data XKB_xkb_context_get_user_data
#define xkb_context_include_path_append XKB_xkb_context_include_path_append
#define xkb_context_include_path_append_default XKB_xkb_context_include_path_append_default
#define xkb_context_include_path_reset_defaults XKB_xkb_context_include_path_reset_defaults
#define xkb_context_include_path_clear XKB_xkb_context_include_path_clear
#define xkb_context_num_include_paths XKB_xkb_context_num_include_paths
#define xkb_context_include_path_get XKB_xkb_context_include_path_get
#define xkb_context_set_log_level XKB_xkb_context_set_log_level
#define xkb_context_get_log_level XKB_xkb_context_get_log_level
#define xkb_context_set_log_verbosity XKB_xkb_context_set_log_verbosity
#define xkb_context_get_log_verbosity XKB_xkb_context_get_log_verbosity
#define xkb_context_set_log_fn XKB_xkb_context_set_log_fn
#define xkb_keymap_new_from_names XKB_xkb_keymap_new_from_names
#define xkb_keymap_new_from_file XKB_xkb_keymap_new_from_file
#define xkb_keymap_new_from_string XKB_xkb_keymap_new_from_string
#define xkb_keymap_new_from_buffer XKB_xkb_keymap_new_from_buffer
#define xkb_keymap_ref XKB_xkb_keymap_ref
#define xkb_keymap_unref XKB_xkb_keymap_unref
#define xkb_keymap_get_as_string XKB_xkb_keymap_get_as_string
#define xkb_keymap_min_keycode XKB_xkb_keymap_min_keycode
#define xkb_keymap_max_keycode XKB_xkb_keymap_max_keycode
#define xkb_keymap_key_for_each XKB_xkb_keymap_key_for_each
#define xkb_keymap_key_get_name XKB_xkb_keymap_key_get_name
#define xkb_keymap_key_by_name XKB_xkb_keymap_key_by_name
#define xkb_keymap_num_mods XKB_xkb_keymap_num_mods
#define xkb_keymap_mod_get_name XKB_xkb_keymap_mod_get_name
#define xkb_keymap_mod_get_index XKB_xkb_keymap_mod_get_index
#define xkb_keymap_num_layouts XKB_xkb_keymap_num_layouts
#define xkb_keymap_layout_get_name XKB_xkb_keymap_layout_get_name
#define xkb_keymap_layout_get_index XKB_xkb_keymap_layout_get_index
#define xkb_keymap_num_leds XKB_xkb_keymap_num_leds
#define xkb_keymap_led_get_name XKB_xkb_keymap_led_get_name
#define xkb_keymap_led_get_index XKB_xkb_keymap_led_get_index
#define xkb_keymap_num_layouts_for_key XKB_xkb_keymap_num_layouts_for_key
#define xkb_keymap_num_levels_for_key XKB_xkb_keymap_num_levels_for_key
#define xkb_keymap_key_get_mods_for_level XKB_xkb_keymap_key_get_mods_for_level
#define xkb_keymap_key_get_syms_by_level XKB_xkb_keymap_key_get_syms_by_level
#define xkb_keymap_key_repeats XKB_xkb_keymap_key_repeats
#define xkb_state_new XKB_xkb_state_new
#define xkb_state_ref XKB_xkb_state_ref
#define xkb_state_unref XKB_xkb_state_unref
#define xkb_state_get_keymap XKB_xkb_state_get_keymap
#define xkb_state_update_key XKB_xkb_state_update_key
#define xkb_state_update_mask XKB_xkb_state_update_mask
#define xkb_state_key_get_syms XKB_xkb_state_key_get_syms
#define xkb_state_key_get_utf8 XKB_xkb_state_key_get_utf8
#define xkb_state_key_get_utf32 XKB_xkb_state_key_get_utf32
#define xkb_state_key_get_one_sym XKB_xkb_state_key_get_one_sym
#define xkb_state_key_get_layout XKB_xkb_state_key_get_layout
#define xkb_state_key_get_level XKB_xkb_state_key_get_level
#define xkb_state_serialize_mods XKB_xkb_state_serialize_mods
#define xkb_state_serialize_layout XKB_xkb_state_serialize_layout
#define xkb_state_mod_name_is_active XKB_xkb_state_mod_name_is_active
#define xkb_state_mod_names_are_active XKB_xkb_state_mod_names_are_active
#define xkb_state_mod_index_is_active XKB_xkb_state_mod_index_is_active
#define xkb_state_mod_indices_are_active XKB_xkb_state_mod_indices_are_active
#define xkb_state_key_get_consumed_mods2 XKB_xkb_state_key_get_consumed_mods2
#define xkb_state_key_get_consumed_mods XKB_xkb_state_key_get_consumed_mods
#define xkb_state_mod_index_is_consumed2 XKB_xkb_state_mod_index_is_consumed2
#define xkb_state_mod_index_is_consumed XKB_xkb_state_mod_index_is_consumed
#define xkb_state_mod_mask_remove_consumed XKB_xkb_state_mod_mask_remove_consumed
#define xkb_state_layout_name_is_active XKB_xkb_state_layout_name_is_active
#define xkb_state_layout_index_is_active XKB_xkb_state_layout_index_is_active
#define xkb_state_led_name_is_active XKB_xkb_state_led_name_is_active
#define xkb_state_led_index_is_active XKB_xkb_state_led_index_is_active
#endif // FENNEC_PLATFORM_LINUX_XKB_LIB_XKB_H

View File

@@ -1,70 +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/>.
// =====================================================================================================================
#ifndef FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H
#define FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H
#include <EGL/egl.h>
#include <fennec/platform/interface/gfxcontext.h>
#include <fennec/platform/opengl/egl/fwd.h>
namespace fennec
{
class eglcontext : public gfxcontext {
public:
eglcontext(display* display);
~eglcontext() override;
bool connected() override;
int32_t get_version_major() override { return _eglvmajor; }
int32_t get_version_minor() override { return _eglvminor; }
int32_t get_version() override { return _eglctype; }
const cstring& get_name() override;
bool check_extension(const cstring& ext) override;
gfxsurface* create_surface(window* window) override;
void make_current(gfxsurface* surface) override;
EGLDisplay get_egl_display() {
return _egldisplay;
}
EGLDisplay get_egl_context() {
return _eglcontext;
}
EGLDisplay get_egl_config() {
return _eglconfig;
}
private:
EGLDisplay _egldisplay;
EGLContext _eglcontext;
EGLConfig _eglconfig;
EGLint _eglvmajor, _eglvminor, _eglctype;
cstring _extensions;
void cleanup();
};
}
#endif // FENNEC_PLATFORM_OPENGL_EGL_CONTEXT_H

View File

@@ -17,7 +17,7 @@
// ===================================================================================================================== // =====================================================================================================================
/// ///
/// \file gfxsurface.h /// \file sdlwindow.h
/// \brief /// \brief
/// ///
/// ///
@@ -28,49 +28,40 @@
/// ///
/// ///
#ifndef FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H #ifndef FENNEC_PLATFORM_SDL_SDLWINDOW_H
#define FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H #define FENNEC_PLATFORM_SDL_SDLWINDOW_H
#include <fennec/lang/types.h>
#include <fennec/lang/typeuuid.h>
#include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/window.h> #include <fennec/platform/interface/window.h>
namespace fennec namespace fennec
{ {
class gfxsurface : public typed<gfxsurface> { class sdlwindow : public window {
public: public:
virtual ~gfxsurface() = default; sdlwindow(window* parent, const config& cfg);
virtual void resize(size_t width, size_t height) { bool running() override;
_width = width;
_height = height;
}
gfxcontext* get_context() { void set_fullscreen(bool) override;
return _context; void set_borderless(bool) override;
}
window* get_window() { void grab_mouse(bool) override;
return _window; void grab_keyboard(bool) override;
}
void set_title(const cstring&) override;
void set_title(const string&) override;
void set_progress(bool, float) override;
void vsync(int8_t) override;
protected: void begin_frame() override;
gfxcontext* _context; void end_frame() override;
window* _window;
size_t _width, _height; private:
template<typename SurfaceT>
gfxsurface(gfxcontext* ctx, window* window, SurfaceT* type)
: typed(type)
, _context(ctx)
, _window(window)
, _width(window->get_width()), _height(window->get_height()) {
}
}; };
} }
#endif // FENNEC_PLATFORM_INTERFACE_GFXSURFACE_H #endif // FENNEC_PLATFORM_SDL_SDLWINDOW_H

View File

@@ -27,8 +27,8 @@ namespace fennec
class unix_platform : public platform { class unix_platform : public platform {
public: public:
template<typename PlatformT> template<typename PlatformT>
explicit unix_platform(const cstring& name, PlatformT*) explicit unix_platform(const cstring& name, PlatformT* type)
: platform(name, (PlatformT*)(nullptr)) { : platform(name, type) {
} }
shared_object* load_object(const cstring& file) override; shared_object* load_object(const cstring& file) override;

View File

@@ -16,22 +16,31 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H ///
#define FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H /// \file forward.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#include <fennec/platform/interface/platform.h> #ifndef FENNEC_RENDERERS_INTERFACE_FORWARD_H
#define FENNEC_RENDERERS_INTERFACE_FORWARD_H
namespace fennec namespace fennec
{ {
namespace libwayland class gfxpass; // Overarching rendering scheme
{ class gfxcontext; // Globals for an API's context
class gfxresourcepool; // Handles resource creation, allocation, and mapping
bool load_symbols(platform* platform); class gfxpass; // A pass of the renderer, holds a set of subpasses with one coherent objective
void unload_symbols(platform* platform); 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
#endif // FENNEC_PLATFORM_LINUX_WAYLAND_DYN_H

View File

@@ -0,0 +1,78 @@
// =====================================================================================================================
// 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/lang/types.h>
#include <fennec/langproc/strings/string.h>
#include <fennec/renderers/interface/forward.h>
#include <fennec/renderers/interface/gfxresourcepool.h>
namespace fennec
{
class gfxcontext {
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;
gfxresourcepool resources;
gfxcontext& operator=(const gfxcontext&) = delete;
gfxcontext& operator=(gfxcontext&&) = delete;
virtual gfxpass* create_pass() = 0;
protected:
private:
};
}
#endif // FENNEC_RENDERERS_INTERFACE_GFXCONTEXT_H

View File

@@ -16,49 +16,45 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // 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 #ifndef FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H #define FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H
#include <fennec/lang/types.h>
#include <fennec/langproc/strings/string.h> #include <fennec/langproc/strings/string.h>
#include <fennec/lang/typeuuid.h> #include <fennec/renderers/interface/forward.h>
#include <fennec/platform/interface/fwd.h>
#include <fennec/platform/interface/window.h>
namespace fennec namespace fennec
{ {
class gfxcontext : public typed<gfxcontext> { ///
/// \brief Defines an interface that holds a series of passes with one coherent objective
/// \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 gfxpass {
public: public:
const string name; gfxsubpass* add_subpass();
virtual bool connected() = 0; private:
virtual const cstring& get_name() = 0;
virtual int32_t get_version_major() = 0;
virtual int32_t get_version_minor() = 0;
virtual int32_t get_version() = 0;
virtual bool check_extension(const cstring& ext) = 0; };
virtual void make_current(gfxsurface* surface) = 0;
virtual gfxsurface* create_surface(window* window) = 0; class gfxsubpass {
virtual ~gfxcontext() = default;
display* get_display() {
return _display;
}
protected:
display* _display;
template<typename ContextT>
gfxcontext(display* display, const cstring& name, ContextT* type)
: typed(type)
, name(name)
, _display(display) {
}
}; };
} }
#endif // FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H #endif // FENNEC_PLATFORM_INTERFACE_GFXCONTEXT_H

View File

@@ -16,22 +16,28 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#ifndef FENNEC_PLATFORM_LINUX_XKB_DYN_H ///
#define FENNEC_PLATFORM_LINUX_XKB_DYN_H /// \file gfxresourcepool.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#include <fennec/platform/interface/platform.h> #ifndef FENNEC_RENDERERS_INTERFACE_GFXRESOURCEPOOL_H
#define FENNEC_RENDERERS_INTERFACE_GFXRESOURCEPOOL_H
namespace fennec namespace fennec
{ {
namespace libxkbcommon class gfxresourcepool {
{
bool load_symbols(platform* platform); };
void unload_symbols(platform* platform);
} }
} #endif // FENNEC_RENDERERS_INTERFACE_GFXRESOURCEPOOL_H
#endif // FENNEC_PLATFORM_LINUX_XKB_DYN_H

View File

@@ -17,7 +17,7 @@
// ===================================================================================================================== // =====================================================================================================================
/// ///
/// \file fwd.h /// \file gfxsubpass.h
/// \brief /// \brief
/// ///
/// ///
@@ -28,15 +28,14 @@
/// ///
/// ///
#ifndef FENNEC_PLATFORM_OPENGL_EGL_FWD_H #ifndef FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H
#define FENNEC_PLATFORM_OPENGL_EGL_FWD_H #define FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H
namespace fennec namespace fennec
{ {
class eglcontext;
class eglsurface;
} }
#endif // FENNEC_PLATFORM_OPENGL_EGL_FWD_H #endif // FENNEC_RENDERERS_INTERFACE_GFXSUBPASS_H

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.30) cmake_minimum_required(VERSION 3.28)
project(fennec-metaprogramming) project(fennec-metaprogramming)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
@@ -18,4 +18,4 @@ add_custom_command(
add_custom_target( add_custom_target(
metaprogramming metaprogramming
DEPENDS .metaprogramming DEPENDS .metaprogramming
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
planning/ControlScene.ods Normal file

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

26
planning/RENDERERS.md Normal file
View File

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

View File

@@ -19,6 +19,7 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <bits/posix2_lim.h>
#include <fennec/langproc/filesystem/file.h> #include <fennec/langproc/filesystem/file.h>
#include <fennec/langproc/filesystem/path.h> #include <fennec/langproc/filesystem/path.h>
@@ -921,7 +922,7 @@ bool file::eof() const {
char file::getc() { char file::getc() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State"); assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(not(_mode & fmode_wide), "Attempted Byte Operation on Wide File"); assert(not(_mode & fmode_wide), "Attempted Wide Operation on Byte File");
// Check if there is a file // Check if there is a file
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -933,7 +934,7 @@ char file::getc() {
wchar_t file::getwc() { wchar_t file::getwc() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State"); assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(_mode & fmode_wide, "Attempted Wide Operation on Byte File"); assert(_mode & fmode_wide, "Attempted Byte Operation on Wide File");
// Check if there is a file // Check if there is a file
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -959,92 +960,6 @@ size_t file::read(void* data, size_t size, size_t n) {
return read; return read;
} }
string file::getline() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(not(_mode & fmode_wide), "Attempted Byte Operation on Wide File");
// Check if there is a file
if (_handle == nullptr) {
return 0;
}
// Read the next line;
char* line = nullptr;
size_t size = 0;
const size_t read = ::getline(&line, &size, _handle);
if (read == npos && ferror(_handle)) {
_error = strerror(errno);
if (line) free(line);
return string("");
}
string res = string(line, read);
free(line);
return res;
}
wstring file::getwline() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(_mode & fmode_wide, "Attempted Wide Operation on Byte File");
// Check if there is a file
if (_handle == nullptr) {
return _wstring{ L"" };
}
// Read the next line;
wchar_t arr[257] = { L'\0' };
wcstring buff = arr;
wstring res{L""};
// read until first newline or end of file
while (fgetws(arr, 257, _handle)) {
res += wcstring(arr, buff.length());
if (buff.length() < 256 || buff[256] == L'\n') {
return res;
}
}
_error = strerror(errno);
return wstring(L"");
}
bool file::putc(char c) {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(not(_mode & fmode_wide), "Attempted Byte Operation on Wide File");
// Check if there is a file
if (_handle == nullptr) {
return false;
}
int res;
if ((res = fputc(c, _handle)) != c && res != EOF) {
_error = strerror(errno);
return true;
}
return false;
}
bool file::putwc(wchar_t c) {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(_mode & fmode_wide, "Attempted Wide Operation on Byte File");
// Check if there is a file
if (_handle == nullptr) {
return false;
}
int res;
if ((res = fputc(c, _handle)) != c && res != EOF) {
_error = strerror(errno);
return true;
}
return false;
}
size_t file::write(const void* data, size_t size, size_t n) { size_t file::write(const void* data, size_t size, size_t n) {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State"); assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
@@ -1063,4 +978,92 @@ size_t file::write(const void* data, size_t size, size_t n) {
return r; return r;
} }
string file::getline() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(not(_mode & fmode_wide), "Attempted Wide Operation on Byte File");
// Check if there is a file
if (_handle == nullptr) {
return string{ "" };
}
// Read the next line;
char arr[LINE_MAX + 2] = { L'\0' };
cstring buff = arr;
string res{""};
// read until first newline or end of file
while (fgets(arr, LINE_MAX + 2, _handle)) {
res += cstring(arr, buff.length());
if (buff.length() < LINE_MAX || buff[LINE_MAX] == L'\n') {
return res;
}
}
_error = strerror(errno);
return string("");
}
wstring file::getwline() {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(_mode & fmode_wide, "Attempted Byte Operation on Wide File");
// Check if there is a file
if (_handle == nullptr) {
return _wstring{ L"" };
}
// Read the next line;
wchar_t arr[LINE_MAX + 2] = { L'\0' };
wcstring buff = arr;
wstring res{L""};
// read until first newline or end of file
while (fgetws(arr, LINE_MAX + 2, _handle)) {
res += wcstring(arr, buff.length());
if (buff.length() < LINE_MAX || buff[LINE_MAX] == L'\n') {
return res;
}
}
_error = strerror(errno);
return wstring(L"");
}
bool file::putc(char c) {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(not(_mode & fmode_wide), "Attempted Wide Operation on Byte File");
// Check if there is a file
if (_handle == nullptr) {
return false;
}
int res;
if ((char)(res = fputc(c, _handle)) != c && res != EOF) {
_error = strerror(errno);
return true;
}
return false;
}
bool file::putwc(wchar_t c) {
assert(_error == nullptr, "Attempted an Operation on a File in an Errored State");
assert(_mode & fmode_wide, "Attempted Byte Operation on Wide File");
// Check if there is a file
if (_handle == nullptr) {
return false;
}
int res;
if ((wchar_t)(res = fputwc(c, _handle)) != c && res != EOF) {
_error = strerror(errno);
return true;
}
return false;
}
} }

View File

@@ -16,7 +16,6 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#include <fennec/platform/interface/display.h>
#include <fennec/platform/interface/platform.h> #include <fennec/platform/interface/platform.h>
namespace fennec namespace fennec
@@ -37,42 +36,17 @@ static constexpr void insert_driver(list<platform::driver<CtorT>>& drvrs, CtorT
} }
void platform::initialize() { void platform::initialize() {
load_display();
_display->select_context();
} }
void platform::shutdown() { void platform::shutdown() {
delete _display;
} }
void platform::load_display() { window* platform::create_window(const window::config&) {
auto& globals = _get_globals(); return nullptr;
for (auto it : globals.displays) {
_display = it.constructor(this);
if (_display != nullptr) {
return;
}
}
} }
void platform::add_driver(display_ctor ctor, int priority) { void platform::register_window_driver(window_driver&& driver) {
auto& globals = _get_globals(); globals.windows.insert(fennec::forward<window_driver>(driver));
insert_driver(globals.displays, ctor, priority);
} }
void platform::add_driver(input_ctor ctor, int priority) {
auto& globals = _get_globals();
insert_driver(globals.inputs, ctor, priority);
} }
void platform::add_driver(gfxctx_ctor ctor, int priority) {
auto& globals = _get_globals();
insert_driver(globals.graphics, ctor, priority);
}
platform::global_context& platform::_get_globals() {
static global_context ctx;
return ctx;
}
}

View File

@@ -29,11 +29,9 @@ STATIC_CONSTRUCTOR(_init_linux) {
} }
void linux_platform::initialize() { void linux_platform::initialize() {
platform::initialize();
} }
void linux_platform::shutdown() { void linux_platform::shutdown() {
platform::shutdown();
} }
} }

View File

@@ -1,140 +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/>.
// =====================================================================================================================
#include <fennec/platform/linux/wayland/display.h>
#include <fennec/platform/linux/wayland/lib/loader.h>
#include <fennec/platform/linux/wayland/lib/wayland.h>
#include <fennec/lang/startup.h>
#include <fennec/platform/linux/wayland/window.h>
#include <fennec/platform/linux/wayland/lib/headers/wayland-client-protocols.h>
namespace fennec
{
static display* _create_wayland_display(platform* platform) {
wayland_display* display = new wayland_display(platform);
if (not display->connected()) {
delete display, display = nullptr;
}
return display;
}
STATIC_CONSTRUCTOR(_wayland_init) {
platform::add_driver(_create_wayland_display, 1);
}
wayland_display::wayland_display(platform* platform)
: display(platform, "wayland", this)
, _handle(nullptr)
, _registry(nullptr)
, _compositor(nullptr)
, _seat(nullptr)
, _shm(nullptr)
, _fifo(false) {
static constexpr wl_registry_listener listener = {
listen_global, listen_global_remove
};
// Load libwayland.so
libwayland::load_symbols(_platform);
// Get handles
_handle = wl_display_connect(nullptr);
if (not _handle) {
cleanup();
return;
}
// Get the wayland registry
_registry = wl_display_get_registry(_handle);
if (not _registry) {
cleanup();
return;
}
// Add listener for interfaces
wl_registry_add_listener(_registry, &listener, this);
wl_display_roundtrip(_handle);
// Check for fifo v1, wayland's builtin fifo only allows one frame to be in flight at a time
if (not _fifo) {
assert(_fifo, "Compositor does not support fifo-v1 protocol, falling back to other display protocols.");
cleanup();
}
}
wayland_display::~wayland_display() {
if (_handle) {
cleanup();
}
}
bool wayland_display::connected() const {
return _handle != nullptr;
}
window* wayland_display::create_window(window* parent) {
return new wayland_window(this, static_cast<wayland_window*>(parent));
}
void wayland_display::cleanup() {
// Cleanup members
if (_compositor) wl_compositor_destroy(_compositor);
if (_registry) wl_registry_destroy(_registry);
if (_handle) {
wl_display_flush(_handle);
wl_display_disconnect(_handle);
}
_compositor = nullptr;
_registry = nullptr;
_handle = nullptr;
libwayland::unload_symbols(_platform);
}
void wayland_display::listen_global(void* data, wl_registry* registry, uint32_t name, const char* itfc, uint32_t version) {
static constexpr wl_seat_listener seat_listener = {
listen_seat, nullptr
};
wayland_display* device = static_cast<wayland_display*>(data);
const cstring interface = cstring(itfc, strlen(itfc) + 1);
if (interface == "wl_compositor") {
device->_compositor = static_cast<wl_compositor*>(wl_registry_bind(registry, name, &wl_compositor_interface, version));
} else if (interface == "wl_seat") {
device->_seat = static_cast<wl_seat*>(wl_registry_bind(registry, name, &wl_seat_interface, version));
wl_seat_add_listener(device->_seat, &seat_listener, device);
} else if (interface == "wp_fifo_manager_v1") {
device->_fifo = true;
}
}
void wayland_display::listen_global_remove(void*, wl_registry*, uint32_t) {
}
void wayland_display::listen_seat(void*, wl_seat*, uint32_t) {
}
}

View File

@@ -1,86 +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/>.
// =====================================================================================================================
#include <fennec/platform/linux/wayland/lib/headers/wayland-client-protocols.h>
#include <fennec/platform/linux/wayland/lib/loader.h>
#define FENNEC_LIB(name) bool FENNEC_HAS_LIB_##name;
#define FENNEC_SYMBOL(ret, fn, ...) using WAYLAND_sym_##fn = ret(*)(__VA_ARGS__); \
WAYLAND_sym_##fn WAYLAND_##fn;
#define FENNEC_GLOBAL(type, name) type* WAYLAND_##name;
#include <fennec/platform/linux/wayland/lib/sym.h>
namespace fennec
{
namespace libwayland
{
using shared_object = platform::shared_object;
struct shared_lib {
shared_object* obj;
const cstring name;
};
static int _load_count = 0;
// Create private variables
#define FENNEC_LIB(lib) static shared_lib _FENNEC_LIB_##lib = { nullptr, FENNEC_LIB_##lib };
#include <fennec/platform/linux/wayland/lib/sym.h>
bool load_symbols(platform* platform) {
if (_load_count++ != 0) {
return true;
}
shared_lib* current_lib = nullptr;
#define FENNEC_LIB(lib) _FENNEC_LIB_##lib.obj = platform->load_object(_FENNEC_LIB_##lib.name); \
FENNEC_HAS_LIB_##lib = _FENNEC_LIB_##lib.obj != nullptr; \
if(not FENNEC_HAS_LIB_##lib) { \
unload_symbols(platform); \
return false; \
} \
current_lib = &_FENNEC_LIB_##lib;
#define FENNEC_SYMBOL(ret, fn, ...) WAYLAND_##fn = (WAYLAND_sym_##fn)(platform->find_symbol(current_lib->obj, #fn)); \
assertf(WAYLAND_##fn != nullptr, "Failed to find symbol: " #fn);
#define FENNEC_GLOBAL(type, name) WAYLAND_##name = (type*)(platform->find_symbol(current_lib->obj, #name)); \
assertf(WAYLAND_##name != nullptr, "Failed to find global: " #name);
#include <fennec/platform/linux/wayland/lib/sym.h>
return true;
}
void unload_symbols(platform* platform) {
if (--_load_count != 0) {
return;
}
#define FENNEC_LIB(lib) platform->unload_object(_FENNEC_LIB_##lib.obj); \
_FENNEC_LIB_##lib.obj = nullptr;
#define FENNEC_SYMBOL(ret, fn, ...) WAYLAND_##fn = nullptr;
#define FENNEC_GLOBAL(type, name) WAYLAND_##name = nullptr;
#include <fennec/platform/linux/wayland/lib/sym.h>
}
}
}

View File

@@ -1,139 +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/>.
// =====================================================================================================================
#include <fennec/platform/interface/gfxcontext.h>
#include <fennec/platform/interface/gfxsurface.h>
#include <fennec/platform/linux/wayland/window.h>
#include <fennec/platform/linux/wayland/lib/wayland.h>
namespace fennec
{
bool wayland_window::running() {
return _surface != nullptr;
}
void wayland_window::configure(const config& config) {
_config = config;
}
bool wayland_window::initialize(bool) {
wayland_display* display = static_cast<wayland_display*>(_display);
_handle = wl_compositor_create_surface(display->get_compositor());
_surface = display->get_context()->create_surface(this);
return false;
}
bool wayland_window::shutdown() {
delete _surface;
wl_surface_destroy(_handle);
_display = nullptr;
_surface = nullptr;
_shell = nullptr;
_handle = nullptr;
return false;
}
bool wayland_window::set_title(const cstring& title) {
if (not _config) {
return true;
}
_config->title = title;
wl_shell_surface_set_title(_shell, _config->title.cstr());
return false;
}
bool wayland_window::set_title(const string& title) {
if (not _config) {
return true;
}
_config->title = title;
wl_shell_surface_set_title(_shell, _config->title.cstr());
return false;
}
bool wayland_window::set_width(size_t w) {
if (not _config) {
return true;
}
_config->width = w;
_surface->resize(_config->width, _config->height);
return false;
}
bool wayland_window::set_height(size_t h) {
if (not _config) {
return true;
}
_config->height = h;
_surface->resize(_config->width, _config->height);
return false;
}
bool wayland_window::resize(size_t w, size_t h) {
if (not _config) {
return true;
}
_config->width = w;
_config->height = h;
_surface->resize(_config->width, _config->height);
return false;
}
bool wayland_window::set_resizable(bool) {
return false; // TODO
}
bool wayland_window::set_fullscreen_mode(fullscreen_mode) {
return false; // TODO
}
bool wayland_window::grab_keyboard(bool) {
return false; // TODO
}
bool wayland_window::grab_mouse(bool) {
return false; // TODO
}
bool wayland_window::block_screensaver(bool) {
return false; // TODO
}
wayland_window::wayland_window(wayland_display* display, wayland_window* parent)
: window(display, parent, this)
, _handle()
, _shell()
, _nfs_width(0), _nfs_height(0) {
}
wayland_window::~wayland_window() {
wayland_window::shutdown();
}
}

View File

@@ -1,87 +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/>.
// =====================================================================================================================
#include <fennec/platform/linux/xkb/lib/xkb.h>
#include <fennec/platform/linux/xkb/lib/loader.h>
#include <fennec/platform/interface/platform.h>
#define FENNEC_LIB(name) bool FENNEC_HAS_LIB_##name;
#define FENNEC_SYMBOL(ret, fn, ...) using XKB_sym_##fn = ret(*)(__VA_ARGS__); \
XKB_sym_##fn XKB_##fn;
#define FENNEC_GLOBAL(type, name) type* XKB_##name;
#include <fennec/platform/linux/xkb/lib/sym.h>
namespace fennec
{
namespace libxkbcommon
{
using shared_object = platform::shared_object;
struct shared_lib {
shared_object* obj;
const cstring name;
};
static int _load_count = 0;
// Create private variables
#define FENNEC_LIB(lib) static shared_lib _FENNEC_LIB_##lib = { nullptr, FENNEC_LIB_##lib };
#include <fennec/platform/linux/xkb/lib/sym.h>
bool load_symbols(platform* platform) {
if (_load_count++ != 0) {
return true;
}
shared_lib* current_lib = nullptr;
#define FENNEC_LIB(lib) _FENNEC_LIB_##lib.obj = platform->load_object(_FENNEC_LIB_##lib.name); \
FENNEC_HAS_LIB_##lib = _FENNEC_LIB_##lib.obj != nullptr; \
if(not FENNEC_HAS_LIB_##lib) { \
unload_symbols(platform); \
return false; \
} \
current_lib = &_FENNEC_LIB_##lib;
#define FENNEC_SYMBOL(ret, fn, ...) XKB_##fn = (XKB_sym_##fn)(platform->find_symbol(current_lib->obj, #fn)); \
assertf(XKB_##fn != nullptr, "Failed to find symbol: " #fn);
#define FENNEC_GLOBAL(type, name) XKB_##name = (type*)(platform->find_symbol(current_lib->obj, #name)); \
assertf(XKB_##name != nullptr, "Failed to find global: " #name);
#include <fennec/platform/linux/xkb/lib/sym.h>
return true;
}
void unload_symbols(platform* platform) {
if (--_load_count != 0) {
return;
}
#define FENNEC_LIB(lib) platform->unload_object(_FENNEC_LIB_##lib.obj); \
_FENNEC_LIB_##lib.obj = nullptr;
#define FENNEC_SYMBOL(ret, fn, ...) XKB_##fn = nullptr;
#define FENNEC_GLOBAL(type, name) XKB_##name = nullptr;
#include <fennec/platform/linux/xkb/lib/sym.h>
}
}
}

View File

@@ -1,166 +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/>.
// =====================================================================================================================
#include <fennec/langproc/filesystem/file.h>
#include <fennec/lang/startup.h>
#include <fennec/platform/interface/display.h>
#include <fennec/platform/interface/platform.h>
#include <fennec/platform/opengl/egl/context.h>
#include <fennec/platform/opengl/egl/surface.h>
#include <GL/gl.h>
namespace fennec
{
static gfxcontext* _create_egl_context(display* display) {
eglcontext* ctx = new eglcontext(display);
if (not ctx->connected()) {
delete ctx, ctx = nullptr;
}
return ctx;
}
STATIC_CONSTRUCTOR(_egl_init) {
platform::add_driver(_create_egl_context, 1);
}
eglcontext::eglcontext(display* display)
: gfxcontext(display, "EGL", this)
, _egldisplay(nullptr), _eglcontext(nullptr)
, _eglconfig(), _eglvmajor(0), _eglvminor(0)
, _eglctype(0), _extensions(nullptr) {
// Get the display format
const display::pixel_format& fmt = _display->get_color_format();
// Currently empty
EGLint context_attrs[] = {
EGL_NONE
};
// Configure the depth and rgb bit-depth
EGLint config_attrs[] = {
EGL_SURFACE_TYPE,
EGL_WINDOW_BIT,
EGL_DEPTH_SIZE, fmt.depth,
EGL_RED_SIZE, fmt.r,
EGL_RED_SIZE, fmt.g,
EGL_RED_SIZE, fmt.b,
EGL_RENDERABLE_TYPE,
EGL_OPENGL_BIT, // 7
EGL_NONE
};
// Attempt to retrieve an egl display from the native display
_egldisplay = eglGetDisplay(_display->get_native_handle());
if (_egldisplay == nullptr) {
cleanup();
return;
}
// Attempt to initialize egl
if (not eglInitialize(_egldisplay, nullptr, nullptr)) {
cleanup();
return;
}
// Attempt to bind to Core OpenGL, otherwise OpenGL ES
if (not eglBindAPI(EGL_OPENGL_API)) {
if (not eglBindAPI(EGL_OPENGL_ES_API)) {
cleanup();
return;
}
config_attrs[7] = EGL_OPENGL_ES_BIT; // Change the support bit to OpenGL ES
}
// Select a configuration
EGLint n;
if (not eglChooseConfig(_egldisplay, config_attrs, &_eglconfig, 1, &n)) {
cleanup();
return;
}
// Create the context
_eglcontext = eglCreateContext(_egldisplay, _eglconfig, EGL_NO_CONTEXT, context_attrs);
if (_eglcontext == nullptr) {
cleanup();
return;
}
// make this the current context so we can retrieve the information below
eglMakeCurrent(_egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, _eglcontext);
// Query available extensions
const char* ptr = eglQueryString(_egldisplay, EGL_EXTENSIONS);
_extensions = { ptr, strlen(ptr) + 1 };
// Query the context and version
eglQueryContext(_egldisplay, _eglcontext, EGL_CONTEXT_CLIENT_TYPE, &_eglctype);
glGetIntegerv(GL_MAJOR_VERSION, &_eglvmajor);
glGetIntegerv(GL_MINOR_VERSION, &_eglvminor);
}
eglcontext::~eglcontext() {
cleanup();
}
bool eglcontext::connected() {
return _eglcontext != nullptr;
}
const cstring& eglcontext::get_name() {
static constexpr cstring opengl = "OpenGL";
static constexpr cstring gles = "GLES";
static constexpr cstring openvg = "OpenVG"; // this should never be used
switch (_eglctype) {
default:
case EGL_OPENGL_API: return opengl;
case EGL_OPENGL_ES_API: return gles;
case EGL_OPENVG_API: return openvg;
}
}
bool eglcontext::check_extension(const cstring& ext) {
return _extensions.find(ext) != _extensions.size();
}
gfxsurface* eglcontext::create_surface(window* window) {
return new eglsurface(this, window);
}
void eglcontext::make_current(gfxsurface* surface) {
eglsurface* eglsurface = static_cast<fennec::eglsurface*>(surface);
eglMakeCurrent(_egldisplay, eglsurface->get_egl_surface(), eglsurface->get_egl_surface(), _eglcontext);
}
void eglcontext::cleanup() {
eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(_display, _eglcontext);
eglTerminate(_display);
eglReleaseThread();
_egldisplay = nullptr;
_eglconfig = nullptr;
_eglcontext = nullptr;
_eglvmajor = 0;
_eglvminor = 0;
}
}

View File

@@ -1,66 +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/>.
// =====================================================================================================================
#include <fennec/platform/opengl/egl/surface.h>
#include <fennec/platform/linux/wayland/lib/wayland.h>
namespace fennec
{
eglsurface::~eglsurface() {
if (_window->is_type<wayland_window>()) {
wl_egl_window_destroy(static_cast<wl_egl_window*>(_handle));
}
}
void eglsurface::resize(size_t width, size_t height) {
gfxsurface::resize(width, height);
if (_window->is_type<wayland_window>()) {
wl_egl_window_resize(static_cast<wl_egl_window*>(_handle), width, height, 0, 0);
}
}
eglsurface::eglsurface(eglcontext* context, window* window)
: gfxsurface(context, window, this)
, _handle(nullptr)
, _surface(nullptr) {
const window::config& config = window->get_config();
if (window->is_type<wayland_window>()) {
_handle = wl_egl_window_create(window->get_native_handle(), config.width, config.height);
}
assert(
_handle != nullptr,
"Failed to create egl window!"
);
eglCreateWindowSurface(
context->get_egl_display(),
context->get_egl_config(),
reinterpret_cast<EGLNativeWindowType>(_handle),
nullptr
);
assert(
EGL_TRUE == eglMakeCurrent(context->get_egl_display(), _surface, _surface, context->get_egl_context()),
"Failed to create egl window!"
);
}
}

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.30) cmake_minimum_required(VERSION 3.28)
project(fennec-test) project(fennec-test)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
@@ -7,6 +7,9 @@ set(CMAKE_C_STANDARD 23)
add_executable(fennec-test add_executable(fennec-test
main.cpp main.cpp
tests/containers/performance/test_iterator_visitor.h tests/containers/performance/test_iterator_visitor.h
tests/containers/test_sequence.h
tests/langproc/test_format.h
tests/containers/test_priority_queue.h
) )
target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}" target_compile_definitions(fennec-test PUBLIC FENNEC_TEST_CWD="${CMAKE_SOURCE_DIR}/bin/${FENNEC_BUILD_NAME}"
@@ -17,4 +20,4 @@ target_link_libraries(fennec-test PRIVATE
-Wl,--whole-archive -Wl,--whole-archive
fennec fennec
-Wl,--no-whole-archive -Wl,--no-whole-archive
) )

View File

@@ -0,0 +1,109 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_TEST_CONTAINERS_BINTREE_H
#define FENNEC_TEST_CONTAINERS_BINTREE_H
#include "../../test.h"
#include <fennec/containers/bintree.h>
namespace fennec
{
namespace test
{
inline void fennec_test_containers_bintree() {
using tree_t = bintree<size_t>;
tree_t test;
constexpr size_t npos = tree_t::npos;
constexpr size_t pre_order [] = { 1, 2, 4, 5, 3, 6 };
constexpr size_t in_order [] = { 4, 2, 5, 1, 3, 6 };
constexpr size_t post_order[] = { 4, 5, 2, 6, 3, 1 };
const size_t n = 50;
for (size_t i = 0; i < n; ++i) {
const size_t parent = rand() % max(test.size(), size_t(1));
const bool side = rand() % 2;
size_t l = side ? test.insert_right(parent, i) : test.insert_left(parent, i);
assertf(test.parent(l) == parent, "Tree Construct Test Failed.");
}
fennec_test_spacer(1);
test.clear();
fennec_test_run(test.empty(), true);
fennec_test_spacer(1);
size_t n1 = test.insert_left(npos, 1);
size_t n2 = test.insert_left(n1, 2);
size_t n3 = test.insert_right(n1, 3);
size_t n4 = test.insert_left(n2, 4);
size_t n5 = test.insert_right(n2, 5);
size_t n6 = test.insert_right(n3, 6);
fennec_test_run(n1 != npos, true);
fennec_test_run(n2 != npos, true);
fennec_test_run(n3 != npos, true);
fennec_test_run(n4 != npos, true);
fennec_test_run(n5 != npos, true);
fennec_test_run(n6 != npos, true);
fennec_test_spacer(1);
size_t i;
i = 0;
test.traverse<tree_t::pre_order>([&](size_t x, size_t) -> uint8_t {
fennec_test_run(x, pre_order[i++]);
return traversal_control_continue;
}, test.root());
fennec_test_spacer(1);
i = 0;
test.traverse<tree_t::in_order>([&](size_t x, size_t) -> uint8_t {
fennec_test_run(x, in_order[i++]);
return traversal_control_continue;
}, test.root());
fennec_test_spacer(1);
i = 0;
test.traverse<tree_t::post_order>([&](size_t x, size_t) -> uint8_t {
fennec_test_run(x, post_order[i++]);
return traversal_control_continue;
}, test.root());
fennec_test_spacer(1);
test.clear();
fennec_test_run(test.empty(), true);
}
}
}
#endif // FENNEC_TEST_CONTAINERS_RDTREE_H

View File

@@ -16,27 +16,41 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#include <fennec/platform/interface/display.h> #ifndef FENNEC_TEST_CONTAINERS_PRIORITY_QUEUE_H
#include <fennec/platform/interface/gfxcontext.h> #define FENNEC_TEST_CONTAINERS_PRIORITY_QUEUE_H
#include <fennec/platform/interface/platform.h>
namespace fennec #include "../../test.h"
#include <cstdlib>
#include <fennec/containers/priority_queue.h>
#include <fennec/containers/sequence.h>
namespace fennec::test
{ {
display::~display() { inline void fennec_test_containers_priority_queue() {
delete _context;
}
void display::select_context() { using type_t = decltype(rand());
if (_context != nullptr) return; sequence<type_t> ref;
priority_queue<type_t> test;
const platform::global_context& globals = platform::get_globals(); size_t n = 50;
for (const auto& ctx : globals.graphics) { for (size_t i = 0; i < n; ++i) {
_context = ctx.constructor(this); type_t v = rand();
if (_context) { test.push(v);
return; ref.insert(v);
} }
fennec_test_run(test.size(), n);
for (type_t x : ref) {
assert(x == test.front(), "Failed Priority Queue Test!");
test.pop();
}
std::cout << "passed" << std::endl;
} }
}
} }
#endif // FENNEC_TEST_CONTAINERS_PRIORITY_QUEUE_H

View File

@@ -55,11 +55,6 @@ inline void fennec_test_containers_rdtree() {
fennec_test_spacer(1); fennec_test_spacer(1);
test.traverse<tree_t::pre_order>([](size_t i, size_t n) -> uint8_t {
assertf(i + 1 == n, "Tree Traverse Test Failed");
return traversal_control_continue;
});
test.erase(0); test.erase(0);
fennec_test_run(test.empty(), true); fennec_test_run(test.empty(), true);

View File

@@ -0,0 +1,76 @@
// =====================================================================================================================
// 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 test_sequence.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_TEST_CONTAINERS_SEQUENCE_H
#define FENNEC_TEST_CONTAINERS_SEQUENCE_H
#include <fennec/containers/sequence.h>
namespace fennec
{
namespace test
{
inline void fennec_test_containers_sequence() {
using type_t = decltype(rand());
dynarray<type_t> ref;
sequence<type_t> test;
const size_t n = 50;
for (size_t i = 0; i < n; ++i) {
type_t v = rand();
ref.push_back(v);
test.insert(v);
}
fennec_test_run(test.size(), n);
type_t p = -1;
size_t c = 0;
for (type_t x : test) {
assertf(x > p, "Failed Sequence Test!");
p = x;
++c;
}
fennec_test_run(c, n);
for (type_t v : ref) {
assertf(test.contains(v), "Failed Sequence Test!");
test.erase(v);
}
fennec_test_run(test.empty(), true);
}
}
}
#endif // FENNEC_TEST_CONTAINERS_SEQUENCE_H

View File

@@ -17,7 +17,7 @@
// ===================================================================================================================== // =====================================================================================================================
/// ///
/// \file surface.h /// \file test_format.h
/// \brief /// \brief
/// ///
/// ///
@@ -28,33 +28,36 @@
/// ///
/// ///
#ifndef FENNEC_PLATFORM_OPENGL_EGL_SURFACE_H #ifndef FENNEC_TEST_LANGPROC_FORMAT_H
#define FENNEC_PLATFORM_OPENGL_EGL_SURFACE_H #define FENNEC_TEST_LANGPROC_FORMAT_H
#include <fennec/langproc/compile/tokenizer.h>
#include <fennec/platform/interface/gfxsurface.h>
#include <fennec/platform/linux/wayland/window.h>
#include <fennec/platform/opengl/egl/context.h>
namespace fennec namespace fennec
{ {
class eglsurface : public gfxsurface { namespace test
public: {
~eglsurface() override;
void resize(size_t width, size_t height) override; inline void fennec_test_langproc_format() {
eglsurface(eglcontext* context, window* window); // tokenizer math = {
// .delimiter { " " },
EGLSurface get_egl_surface() { // .operators {"+-/*="},
return _surface; // .braces { "()" },
} // .escapes { "" },
// .terminator { "" },
private: // };
void* _handle; //
EGLSurface _surface; // const auto res = math.parse("1 + 2 = 3");
}; // fennec_test_run(res.size(), size_t(5));
//
// for (const auto& token : res) {
// std::cout << token.second << ", ";
// }
}
} }
#endif // FENNEC_PLATFORM_OPENGL_EGL_SURFACE_H }
#endif // FENNEC_TEST_LANGPROC_FORMAT_H

View File

@@ -20,6 +20,7 @@
#define FENNEC_TEST_CONTAINERS_H #define FENNEC_TEST_CONTAINERS_H
#include "containers/test_array.h" #include "containers/test_array.h"
#include "containers/test_bintree.h"
#include "containers/test_deque.h" #include "containers/test_deque.h"
#include "containers/test_dynarray.h" #include "containers/test_dynarray.h"
#include "containers/test_graph.h" #include "containers/test_graph.h"
@@ -27,7 +28,9 @@
#include "containers/test_map.h" #include "containers/test_map.h"
#include "containers/test_object_pool.h" #include "containers/test_object_pool.h"
#include "containers/test_optional.h" #include "containers/test_optional.h"
#include "containers/test_priority_queue.h"
#include "containers/test_rdtree.h" #include "containers/test_rdtree.h"
#include "containers/test_sequence.h"
#include "containers/test_set.h" #include "containers/test_set.h"
#include "containers/test_tuple.h" #include "containers/test_tuple.h"
@@ -71,6 +74,21 @@ namespace fennec::test
fennec_test_containers_set(); fennec_test_containers_set();
fennec_test_spacer(3); fennec_test_spacer(3);
fennec_test_subheader("bintree tests");
fennec_test_spacer(2);
fennec_test_containers_bintree();
fennec_test_spacer(3);
fennec_test_subheader("sequence tests");
fennec_test_spacer(2);
fennec_test_containers_sequence();
fennec_test_spacer(3);
fennec_test_subheader("priority queue tests");
fennec_test_spacer(2);
fennec_test_containers_priority_queue();
fennec_test_spacer(3);
fennec_test_subheader("map tests"); fennec_test_subheader("map tests");
fennec_test_spacer(2); fennec_test_spacer(2);
fennec_test_containers_map(); fennec_test_containers_map();

View File

@@ -23,6 +23,7 @@
#include "./langproc/test_strings.h" #include "./langproc/test_strings.h"
#include "./langproc/test_io.h" #include "./langproc/test_io.h"
#include "langproc/test_format.h"
namespace fennec::test namespace fennec::test
{ {
@@ -33,6 +34,11 @@ namespace fennec::test
fennec_test_langproc_strings(); fennec_test_langproc_strings();
fennec_test_spacer(3); fennec_test_spacer(3);
fennec_test_header("format");
fennec_test_spacer(2);
fennec_test_langproc_format();
fennec_test_spacer(3);
fennec_test_header("io"); fennec_test_header("io");
fennec_test_spacer(2); fennec_test_spacer(2);
fennec_test_langproc_io(); fennec_test_langproc_io();

View File

@@ -21,8 +21,6 @@
#include "../test.h" #include "../test.h"
#include <fennec/platform/interface/display.h>
#include <fennec/platform/interface/gfxcontext.h>
#include <fennec/platform/interface/platform.h> #include <fennec/platform/interface/platform.h>
@@ -31,37 +29,6 @@ namespace fennec::test
inline void fennec_test_platform() { inline void fennec_test_platform() {
platform* instance = platform::instance();
instance->initialize();
display* display = instance->get_display();
fennec_test_run(display != nullptr, true);
fennec_test_run(display->get_context() != nullptr, true);
gfxcontext* gfxcontext = display->get_context();
std::cout << gfxcontext->get_name() << " ";
std::cout << gfxcontext->get_version_major() << ".";
std::cout << gfxcontext->get_version_minor() << std::endl;
window::config winconfig = {
string{"fennec_test_platform"},
window::flags_none,
1280, 720,
window::fullscreen_mode::windowed
};
window* window = display->create_window(nullptr);
fennec_test_run(window != nullptr, true);
window->configure(winconfig);
window->initialize(false);
fennec_test_run(window->running(), true);
delete window;
instance->shutdown();
} }
} }