Compare commits

..

1 Commits

Author SHA1 Message Date
Alexandre
f1159d111b switched to imgui docked, docks, but no viewport, to fix 2026-08-06 18:05:41 +02:00
28 changed files with 300 additions and 2941 deletions

View File

@ -11,4 +11,3 @@ CompileFlags:
- -DLOGGER_IMPL - -DLOGGER_IMPL
- -DSERVER_INIT_IMPL - -DSERVER_INIT_IMPL
- -DSERVER_IMPL - -DSERVER_IMPL
- -DLOADER_IMPL

4
.envrc
View File

@ -1 +1,3 @@
use flake FLAKEPATH="/home/alex/Developer/nix/NixOSDots/dev-flakes"
use flake ${FLAKEPATH}/vulkan

View File

@ -1,54 +0,0 @@
name: Build VulkanEngine
on:
push:
branches:
- vkguide
pull_request:
workflow_dispatch:
schedule:
- cron: "@weekly"
jobs:
build:
runs-on: ubuntu-22.04
container: git.alexdelcamp.fr/alexandre_1a/flake-actions:latest
steps:
- name: Checkout (avec submodules récursifs)
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: S'assurer que les flakes sont activés
run: |
mkdir -p ~/.config/nix
grep -q "experimental-features" ~/.config/nix/nix.conf 2>/dev/null || \
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
- name: Build using nix
run: |
nix build .#engine
- name: Bundle
run: |
nix bundle --bundler github:ralismark/nix-appimage .#engine --out-link ./engine-bundle
- name: Upload des artefacts
if: success()
uses: actions/upload-artifact@v3
with:
name: vulkan-engine.zip
path: |
./engine-bundle
if-no-files-found: warn
archive: false
- name: Notify routine
if: always()
run: |
curl \
-H "Title: [Routine] VulkanEngine build" \
-d "Build finished (status: ${{ job.status }})" \
https://ntfy.alexdelcamp.fr/FlakeBuild

View File

@ -1,272 +0,0 @@
name: Build VulkanEngine
on:
push:
branches:
- vkguide
pull_request:
workflow_dispatch:
schedule:
- cron: "0 3 * * 1"
jobs:
# ---------------------------------------------------------------------------
# 1. Nix build: validates the flake build and produces the SPIR-V shaders
# (SPIR-V is OS independent, and slangc is not packaged in Debian).
# ---------------------------------------------------------------------------
nix:
runs-on: ubuntu-latest
container: git.alexdelcamp.fr/alexandre_1a/flake-actions:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Configure
run: |
nix develop --command cmake -S . -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release
- name: Build
run: |
nix develop --command cmake --build build --parallel 2
- name: Upload shaders
uses: actions/upload-artifact@v4
with:
name: shaders
path: build/engine/shaders
- name: Notify progress
if: always()
run: |
curl \
-H "Title: [Routine] Shaders" \
-d "Build finished" \
https://ntfy.alexdelcamp.fr/FlakeBuild
# ---------------------------------------------------------------------------
# 2. Debian 12 builds: portable (static) and bundle (bin/ + lib/)
# Built on glibc 2.36 => runs on Debian 12 and anything newer.
# ---------------------------------------------------------------------------
debug:
needs: nix
runs-on: ubuntu-latest
container: debian:12
strategy:
fail-fast: false
steps:
# git + nodejs must exist before checkout (JS actions run in the container)
- name: Dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
git ca-certificates nodejs curl \
build-essential cmake ninja-build pkg-config \
libwayland-dev libwayland-bin wayland-protocols libxkbcommon-dev \
libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Git safe directory
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download shaders
uses: actions/download-artifact@v4
with:
name: shaders
path: prebuilt-shaders
- name: Configure
run: |
cmake -S . -B build -G Ninja \
--preset debug \
-DVULKANENGINE_FETCH_DEPS=ON \
-DVULKANENGINE_PORTABLE=ON \
-DVULKANENGINE_PREBUILT_SHADERS="$PWD/prebuilt-shaders"
- name: Build
run: cmake --build build --parallel 2
- name: Install
run: cmake --install build --prefix dist --strip
- name: Check binaries
shell: bash
run: |
set -euo pipefail
for b in dist/bin/engine dist/bin/server; do
echo "========== $b =========="
readelf -l "$b" | grep 'program interpreter'
readelf -d "$b" | grep -E 'RPATH|RUNPATH|NEEDED' || true
if strings "$b" | grep -q '/nix/store'; then
echo "ERROR: $b references /nix/store"; exit 1
fi
# The loader must come from volk (dlopen), never from NEEDED
if readelf -d "$b" | grep -q 'libvulkan'; then
echo "ERROR: $b links libvulkan directly"; exit 1
fi
if [ "PORTABLE" = "PORTABLE" ]; then
if readelf -d "$b" | grep -Eq 'libstdc\+\+|libgcc_s'; then
echo "ERROR: $b is not static for libstdc++/libgcc"; exit 1
fi
fi
max=$(objdump -T "$b" | grep -o 'GLIBC_[0-9.]*' | sed 's/GLIBC_//' | sort -uV | tail -1 || true)
echo "Highest GLIBC symbol: ${max:-none}"
if [ -n "$max" ] && [ "$(printf '%s\n%s\n' "$max" 2.36 | sort -V | tail -1)" != "2.36" ]; then
echo "ERROR: needs glibc $max (> 2.36)"; exit 1
fi
if ldd "$b" | grep 'not found'; then
echo "ERROR: unresolved libraries in $b"; exit 1
fi
done
# tar keeps permissions and symlinks; artifact zips do not
- name: Package
run: |
tar -C dist -czf VulkanEngine-DEBUG-linux-x86_64.tar.gz .
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: VulkanEngine-DEBUG-linux-x86_64
path: VulkanEngine-DEBUG-linux-x86_64.tar.gz
- name: Notify progress
if: failure()
run: |
curl \
-H "Title: [Routine] Engine-DEBUG build" \
-d "Build failed (nix: ${{ needs.nix.result }}, release: ${{ needs.debug.result }})" \
https://ntfy.alexdelcamp.fr/FlakeBuild
release:
needs: nix
runs-on: ubuntu-latest
container: debian:12
strategy:
fail-fast: false
matrix:
variant: [PORTABLE, BUNDLE]
steps:
# git + nodejs must exist before checkout (JS actions run in the container)
- name: Dependencies
run: |
apt-get update
apt-get install -y --no-install-recommends \
git ca-certificates nodejs curl \
build-essential cmake ninja-build pkg-config \
libwayland-dev libwayland-bin wayland-protocols libxkbcommon-dev \
libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Git safe directory
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Download shaders
uses: actions/download-artifact@v4
with:
name: shaders
path: prebuilt-shaders
- name: Configure
run: |
cmake -S . -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DVULKANENGINE_FETCH_DEPS=ON \
-DVULKANENGINE_${{ matrix.variant }}=ON \
-DVULKANENGINE_PREBUILT_SHADERS="$PWD/prebuilt-shaders"
- name: Build
run: cmake --build build --parallel 2
- name: Install
run: cmake --install build --prefix dist --strip
- name: Check binaries
shell: bash
run: |
set -euo pipefail
for b in dist/bin/engine dist/bin/server; do
echo "========== $b =========="
readelf -l "$b" | grep 'program interpreter'
readelf -d "$b" | grep -E 'RPATH|RUNPATH|NEEDED' || true
if strings "$b" | grep -q '/nix/store'; then
echo "ERROR: $b references /nix/store"; exit 1
fi
# The loader must come from volk (dlopen), never from NEEDED
if readelf -d "$b" | grep -q 'libvulkan'; then
echo "ERROR: $b links libvulkan directly"; exit 1
fi
if [ "${{ matrix.variant }}" = "PORTABLE" ]; then
if readelf -d "$b" | grep -Eq 'libstdc\+\+|libgcc_s'; then
echo "ERROR: $b is not static for libstdc++/libgcc"; exit 1
fi
fi
max=$(objdump -T "$b" | grep -o 'GLIBC_[0-9.]*' | sed 's/GLIBC_//' | sort -uV | tail -1 || true)
echo "Highest GLIBC symbol: ${max:-none}"
if [ -n "$max" ] && [ "$(printf '%s\n%s\n' "$max" 2.36 | sort -V | tail -1)" != "2.36" ]; then
echo "ERROR: needs glibc $max (> 2.36)"; exit 1
fi
if ldd "$b" | grep 'not found'; then
echo "ERROR: unresolved libraries in $b"; exit 1
fi
done
if [ "${{ matrix.variant }}" = "BUNDLE" ]; then
echo "========== lib/ =========="
ls -la dist/lib
fi
# tar keeps permissions and symlinks; artifact zips do not
- name: Package
run: |
tar -C dist -czf VulkanEngine-${{ matrix.variant }}-linux-x86_64.tar.gz .
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: VulkanEngine-${{ matrix.variant }}-linux-x86_64
path: VulkanEngine-${{ matrix.variant }}-linux-x86_64.tar.gz
- name: Notify progress
if: failure()
run: |
curl \
-H "Title: [Routine] Engine-${{ matrix.variant }} build" \
-d "Build failed (nix: ${{ needs.nix.result }}, release: ${{ needs.release.result }})" \
https://ntfy.alexdelcamp.fr/FlakeBuild
# ---------------------------------------------------------------------------
notify:
needs: [nix, release]
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify routine
run: |
curl \
-H "Title: [Routine] VulkanEngine build" \
-d "Build finished (nix: ${{ needs.nix.result }}, release: ${{ needs.release.result }})" \
https://ntfy.alexdelcamp.fr/FlakeBuild

5
.gitignore vendored
View File

@ -37,11 +37,6 @@ Thumbs.db
# direnv # direnv
.direnv/ .direnv/
# cache
.cache
.cache/*
# Nix flakes # Nix flakes
result result
result-* result-*
.cache/*

12
.gitmodules vendored
View File

@ -1,8 +1,4 @@
[submodule "include/imgui"] [submodule "src/imgui"]
path = include/imgui path = src/imgui
url = https://git.alexdelcamp.fr/Alexandre_1a/imgui.git url = https://github.com/ocornut/imgui.git
branch = docking branch = docking
[submodule "include/CLI11"]
path = include/CLI11
url = https://github.com/CLIUtils/CLI11.git

View File

@ -1,77 +1,18 @@
cmake_minimum_required(VERSION 3.25) # Debian 12 ships 3.25 cmake_minimum_required (VERSION 3.29)
project(VulkanEngine) project(VulkanEngine)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
include(BuildInfo) include(BuildInfo)
include(FetchContent) include(FetchContent)
# LTO #LTO
include(CheckIPOSupported) include(CheckIPOSupported)
check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_ERROR) check_ipo_supported(RESULT LTO_SUPPORTED OUTPUT LTO_ERROR)
# ---------------------------------------------------------------------------
# Build modes
# (default) Nix dev build, deps from the Nix shell
# FETCH_DEPS + PORTABLE Single directory, everything static except
# glibc (and the Vulkan loader, loaded via volk)
# FETCH_DEPS + BUNDLE bin/ + lib/, project libs shared in lib/,
# system libstdc++ / libc / loader are used
# ---------------------------------------------------------------------------
option(VULKANENGINE_PORTABLE
"Build a Linux binary without Nix-specific runtime paths (static libs)"
OFF
)
option(VULKANENGINE_BUNDLE
"Build a Linux bundle using libraries from the bundle directory"
OFF
)
option(VULKANENGINE_FETCH_DEPS
"Fetch dependencies with FetchContent instead of using system/Nix packages"
OFF
)
set(VULKANENGINE_PREBUILT_SHADERS "" CACHE PATH
"Directory containing precompiled .spv files (skips glslang/slangc)"
)
if(VULKANENGINE_PORTABLE AND VULKANENGINE_BUNDLE)
message(FATAL_ERROR "VULKANENGINE_PORTABLE and VULKANENGINE_BUNDLE are mutually exclusive")
endif()
if((VULKANENGINE_PORTABLE OR VULKANENGINE_BUNDLE) AND NOT VULKANENGINE_FETCH_DEPS)
message(FATAL_ERROR
"PORTABLE/BUNDLE builds need -DVULKANENGINE_FETCH_DEPS=ON "
"(Nix libraries must not leak into the result)")
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# RPATH / runtime paths
if(VULKANENGINE_PORTABLE)
message(STATUS "VulkanEngine: PORTABLE build")
set(CMAKE_SKIP_RPATH TRUE)
elseif(VULKANENGINE_BUNDLE)
message(STATUS "VulkanEngine: BUNDLE build")
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# Executables are installed in bin/
# Libraries are installed in lib/
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
# Every shared lib we build ends up here, installed as-is into lib/
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
else()
message(STATUS "VulkanEngine: normal build")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
find_program(GCC_AR NAMES gcc-ar REQUIRED) find_program(GCC_AR NAMES gcc-ar REQUIRED)
find_program(GCC_RANLIB NAMES gcc-ranlib REQUIRED) find_program(GCC_RANLIB NAMES gcc-ranlib REQUIRED)
@ -79,103 +20,19 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_RANLIB "${GCC_RANLIB}") set(CMAKE_RANLIB "${GCC_RANLIB}")
endif() endif()
# --------------------------------------------------------------------------- # Find all package dependencies
# Dependencies find_package( glfw3 REQUIRED )
# --------------------------------------------------------------------------- find_package( glm REQUIRED )
# Same in every mode: no link-time dependency on libvulkan, all Vulkan find_package( VulkanMemoryAllocator CONFIG REQUIRED )
# functions come from volk (otherwise vk*KHR aliases are undefined at link). find_package( fmt REQUIRED )
set(ENGINE_EXTRA_DEFINITIONS # Shader compilers
GLFW_INCLUDE_NONE add_executable (glslang::validator IMPORTED)
VK_NO_PROTOTYPES find_program (GLSLANG_VALIDATOR "glslangValidator" HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
VMA_STATIC_VULKAN_FUNCTIONS=0 set_property (TARGET glslang::validator PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}")
VMA_DYNAMIC_VULKAN_FUNCTIONS=1 find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
)
if(VULKANENGINE_FETCH_DEPS) # fastgltf because it's not in nixpkgs
# Portable = static libs, bundle = shared libs (in lib/)
if(VULKANENGINE_BUNDLE)
set(BUILD_SHARED_LIBS ON)
else()
set(BUILD_SHARED_LIBS OFF)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(VULKAN_HEADERS_ENABLE_MODULE OFF CACHE BOOL "" FORCE)
set(VULKAN_HEADERS_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
set(VULKAN_HEADERS_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
set(VOLK_PULL_IN_VULKAN OFF CACHE BOOL "" FORCE)
set(VOLK_INSTALL OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_INSTALL OFF CACHE BOOL "" FORCE)
set(FMT_INSTALL OFF CACHE BOOL "" FORCE)
set(FMT_TEST OFF CACHE BOOL "" FORCE)
set(SIMDJSON_DEVELOPER_MODE OFF CACHE BOOL "" FORCE)
set(CLI11_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(CLI11_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(GLM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLM_BUILD_LIBRARY OFF CACHE BOOL "" FORCE)
# Keep these versions in sync with your nixpkgs (check the tags exist)
FetchContent_Declare(VulkanHeaders
GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Headers.git
GIT_TAG v1.4.309)
# vulkan/vk_enum_string_helper.h lives here, not in Vulkan-Headers.
# SOURCE_SUBDIR points to a nonexistent dir so MakeAvailable only downloads
# (we use the checked-in header, no need to run its CMake).
FetchContent_Declare(VulkanUtilityLibraries
GIT_REPOSITORY https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git
GIT_TAG v1.4.309
SOURCE_SUBDIR _no_cmake)
FetchContent_Declare(volk
GIT_REPOSITORY https://github.com/zeux/volk.git
GIT_TAG 1.4.304)
FetchContent_Declare(VMA
GIT_REPOSITORY https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
GIT_TAG v3.2.1)
FetchContent_Declare(glfw
GIT_REPOSITORY https://github.com/glfw/glfw.git
GIT_TAG 3.4)
FetchContent_Declare(vk-bootstrap
GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap.git
GIT_TAG v1.4.365)
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 11.0.2)
FetchContent_Declare(CLI11
GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git
GIT_TAG v2.4.2)
FetchContent_Declare(glm
GIT_REPOSITORY https://github.com/g-truc/glm.git
GIT_TAG 1.0.1)
FetchContent_Declare(simdjson
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
GIT_TAG v3.10.1)
# Vulkan headers first: vk-bootstrap and volk pick up Vulkan::Headers
FetchContent_MakeAvailable(VulkanHeaders VulkanUtilityLibraries)
FetchContent_MakeAvailable(volk VMA glfw vk-bootstrap fmt CLI11 glm simdjson)
target_link_libraries(volk PUBLIC Vulkan::Headers)
add_library(vk_utility_headers INTERFACE)
target_include_directories(vk_utility_headers SYSTEM INTERFACE
${vulkanutilitylibraries_SOURCE_DIR}/include)
target_link_libraries(vk_utility_headers INTERFACE Vulkan::Headers)
else()
# Nix path
find_package( volk CONFIG REQUIRED )
find_package( glfw3 REQUIRED )
find_package( glm REQUIRED )
find_package( VulkanMemoryAllocator CONFIG REQUIRED )
find_package( CLI11 REQUIRED )
find_package( simdjson REQUIRED )
endif()
# fastgltf because it's not in nixpkgs (declared after the switch above so it
# inherits BUILD_SHARED_LIBS)
FetchContent_Declare( FetchContent_Declare(
fastgltf fastgltf
GIT_REPOSITORY https://github.com/spnda/fastgltf.git GIT_REPOSITORY https://github.com/spnda/fastgltf.git
@ -183,26 +40,13 @@ FetchContent_Declare(
) )
FetchContent_MakeAvailable(fastgltf) FetchContent_MakeAvailable(fastgltf)
# --------------------------------------------------------------------------- # vk-bootstrap because CMAKE can't find it on NixOS
# Shader compilers (not needed when precompiled shaders are provided) FetchContent_Declare(
# --------------------------------------------------------------------------- vk-bootstrap
if(NOT VULKANENGINE_PREBUILT_SHADERS) GIT_REPOSITORY https://github.com/charles-lunarg/vk-bootstrap.git
add_executable (glslang::validator IMPORTED) GIT_TAG v1.3.295
find_program ( )
GLSLANG_VALIDATOR FetchContent_MakeAvailable(vk-bootstrap)
"glslangValidator"
HINTS $ENV{VULKAN_SDK}/bin
REQUIRED
)
set_property (
TARGET glslang::validator
PROPERTY IMPORTED_LOCATION "${GLSLANG_VALIDATOR}"
)
find_program(SLANGC_EXECUTABLE slangc HINTS $ENV{VULKAN_SDK}/bin REQUIRED)
endif()
# Helper functions to build shaders # Helper functions to build shaders
function(addGlslShader SOURCE OUTPUT_DIR) function(addGlslShader SOURCE OUTPUT_DIR)
@ -247,39 +91,21 @@ endfunction()
# A function to automate executables aditions # A function to automate executables aditions
function ( addBinary BINARY_NAME ) function ( addBinary BINARY_NAME )
cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;SLANG_ENTRIES;LIBS;TEXTURES;MODELS" ${ARGN} ) cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;LIBS;TEXTURES;MODELS" ${ARGN} )
if (DEFINED BINARY_SOURCE) if (DEFINED BINARY_SOURCE)
add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp ) add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp )
endif() endif()
target_include_directories( ${BINARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src ) target_include_directories( ${BINARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src )
# Sets the output dir to have clear separation between binaries # Sets the output dir to have clear separation between binaries
set_target_properties ( set_target_properties ( ${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BINARY_NAME} )
${BINARY_NAME} set_target_properties ( ${BINARY_NAME} PROPERTIES CXX_STANDARD 20 ) # Uses C++20
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${BINARY_NAME}
CXX_STANDARD
20 # C++ 20
CXX_STANDARD_REQUIRED
ON
CXX_EXTENSIONS
OFF
CXX_SCAN_FOR_MODULES
OFF
)
# Sets per binary LTO # Sets per binary LTO
if(LTO_SUPPORTED AND CMAKE_BUILD_TYPE STREQUAL "Release") if(LTO_SUPPORTED AND CMAKE_BUILD_TYPE STREQUAL "Release")
set_target_properties(${BINARY_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) set_target_properties(${BINARY_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
message("Enabled LTO") message("Enabled LTO")
endif() endif()
set_target_properties(${BINARY_NAME} PROPERTIES CXX_SCAN_FOR_MODULES OFF)
# Portable: libstdc++/libgcc statically linked so the binary does not depend
# on the host's version. NOT done for bundle: the shared libs in lib/ use the
# system libstdc++, and mixing two copies in one process is asking for trouble.
if(VULKANENGINE_PORTABLE)
target_link_options(${BINARY_NAME} PRIVATE -static-libstdc++ -static-libgcc)
endif()
# Define VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS to treat VK_ERROR_OUT_OF_DATE_KHR as a success code # Define VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS to treat VK_ERROR_OUT_OF_DATE_KHR as a success code
target_compile_definitions ( target_compile_definitions (
@ -289,33 +115,25 @@ function ( addBinary BINARY_NAME )
$<$<CONFIG:Debug>:DEBUG> # So CMAKE expose a #define DEBUG for debug builds $<$<CONFIG:Debug>:DEBUG> # So CMAKE expose a #define DEBUG for debug builds
# Exposes versions # Exposes versions
BUILD_ID="${ENGINE_VERSION}" BUILD_ID="${ENGINE_VERSION}"
${ENGINE_EXTRA_DEFINITIONS}
) )
if(BINARY_IMGUI) if(BINARY_IMGUI)
target_include_directories(${BINARY_NAME} PRIVATE target_include_directories(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include/imgui ${CMAKE_SOURCE_DIR}/src/imgui
${CMAKE_SOURCE_DIR}/include/imgui/backends ${CMAKE_SOURCE_DIR}/src/imgui/backends
) )
target_sources(${BINARY_NAME} PRIVATE target_sources(${BINARY_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include/imgui/imgui.cpp ${CMAKE_SOURCE_DIR}/src/imgui/imgui.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_draw.cpp ${CMAKE_SOURCE_DIR}/src/imgui/imgui_draw.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_tables.cpp ${CMAKE_SOURCE_DIR}/src/imgui/imgui_tables.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_widgets.cpp ${CMAKE_SOURCE_DIR}/src/imgui/imgui_widgets.cpp
${CMAKE_SOURCE_DIR}/include/imgui/imgui_demo.cpp ${CMAKE_SOURCE_DIR}/src/imgui/imgui_demo.cpp
#${CMAKE_SOURCE_DIR}/include/imgui/imgui_memory_editor.h
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_glfw.cpp ${CMAKE_SOURCE_DIR}/src/imgui/backends/imgui_impl_glfw.cpp
${CMAKE_SOURCE_DIR}/include/imgui/backends/imgui_impl_vulkan.cpp ${CMAKE_SOURCE_DIR}/src/imgui/backends/imgui_impl_vulkan.cpp
) )
# imgui's Vulkan backend must use volk since there is no linked loader
target_compile_definitions(${BINARY_NAME} PRIVATE IMGUI_IMPL_VULKAN_USE_VOLK)
endif() endif()
if(BINARY_LICENSE) if(BINARY_LICENSE)
file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}) file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME})
endif() endif()
@ -323,48 +141,38 @@ function ( addBinary BINARY_NAME )
if(DEFINED BINARY_SHADERS) if(DEFINED BINARY_SHADERS)
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders) set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders)
set(ALL_SPV_FILES "")
set(EXPANDED_SHADERS "")
if(VULKANENGINE_PREBUILT_SHADERS) foreach(SHADER_PATTERN ${BINARY_SHADERS})
# Copy the .spv produced by the Nix job instead of compiling them if(SHADER_PATTERN MATCHES "[*?]")
file(GLOB PREBUILT_SPV CONFIGURE_DEPENDS "${VULKANENGINE_PREBUILT_SHADERS}/*.spv") file(GLOB SHADER_FILES CONFIGURE_DEPENDS ${SHADER_PATTERN})
if(NOT PREBUILT_SPV) list(APPEND EXPANDED_SHADERS ${SHADER_FILES})
message(FATAL_ERROR "No .spv found in ${VULKANENGINE_PREBUILT_SHADERS}") else()
list(APPEND EXPANDED_SHADERS ${SHADER_PATTERN})
endif() endif()
file(COPY ${PREBUILT_SPV} DESTINATION ${SHADER_OUTPUT_DIR}) endforeach()
else()
set(ALL_SPV_FILES "")
set(EXPANDED_SHADERS "")
foreach(SHADER_PATTERN ${BINARY_SHADERS}) foreach(SHADER_SRC ${EXPANDED_SHADERS})
if(SHADER_PATTERN MATCHES "[*?]") if(NOT IS_ABSOLUTE ${SHADER_SRC})
file(GLOB SHADER_FILES CONFIGURE_DEPENDS ${SHADER_PATTERN}) set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC})
list(APPEND EXPANDED_SHADERS ${SHADER_FILES}) endif()
else() get_filename_component(EXT ${SHADER_SRC} EXT)
list(APPEND EXPANDED_SHADERS ${SHADER_PATTERN}) if(EXT STREQUAL ".slang")
endif() addSlangShader(${SHADER_SRC} "${BINARY_SLANG_ENTRIES}" ${SHADER_OUTPUT_DIR})
endforeach() list(APPEND ALL_SPV_FILES ${SPV_FILE})
else()
addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
endif()
endforeach()
foreach(SHADER_SRC ${EXPANDED_SHADERS}) add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES})
if(NOT IS_ABSOLUTE ${SHADER_SRC}) add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME})
set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC})
endif()
get_filename_component(EXT ${SHADER_SRC} EXT)
if(EXT STREQUAL ".slang")
addSlangShader(${SHADER_SRC} "${BINARY_SLANG_ENTRIES}" ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
else()
addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
endif()
endforeach()
add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES})
add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME})
endif()
endif() endif()
if (DEFINED BINARY_LIBS) if (DEFINED BINARY_LIBS)
target_link_libraries ( ${BINARY_NAME} PRIVATE ${BINARY_LIBS} ) target_link_libraries ( ${BINARY_NAME} ${BINARY_LIBS} )
endif() endif()
if (DEFINED BINARY_MODELS) # Adds the 3D models in the binary folder if (DEFINED BINARY_MODELS) # Adds the 3D models in the binary folder
@ -397,73 +205,23 @@ function ( addBinary BINARY_NAME )
endfunction() endfunction()
# --------------------------------------------------------------------------- # Scan the shader folder
# Binaries file(GLOB SHADER_SOURCES CONFIGURE_DEPENDS "shaders/*")
# ---------------------------------------------------------------------------
list(
APPEND
lib_list
# Libs used
glfw
fmt
vk-bootstrap
CLI11::CLI11
fastgltf
)
if(VULKANENGINE_FETCH_DEPS) # Adds the main binary
# No libvulkan at link time: volk loads libvulkan.so.1 at runtime.
# Remove what your code does not use (simdjson, glm...).
list(APPEND lib_list
volk
Vulkan::Headers
vk_utility_headers
GPUOpen::VulkanMemoryAllocator
glm::glm-header-only
simdjson::simdjson
)
else()
# Nix: volk comes from nixpkgs (vulkan-volk); libvulkan is NOT linked
list(APPEND lib_list volk::volk)
endif()
addBinary ( addBinary (
engine engine
SOURCE Engine/main SOURCE Engine/main
# Flags
SHADERS ${SHADER_SOURCES}
SHADERS
LIBS glfw fmt vk-bootstrap vulkan
IMGUI IMGUI
LICENSE LICENSE
SHADERS shaders/*
MODELS *
LIBS ${lib_list}
) )
addBinary ( addBinary (
server server
SOURCE Server/main SOURCE Server/main
) )
# ---------------------------------------------------------------------------
# Install (used for portable / bundle packaging)
# dist/bin/{engine,server,shaders,models,textures}
# dist/lib/*.so* (bundle only)
# dist/LICENSE
# Never bundled: libc, libstdc++, libvulkan, GL, X11, Wayland.
# ---------------------------------------------------------------------------
install(TARGETS engine server RUNTIME DESTINATION bin)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/shaders DESTINATION bin OPTIONAL)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/models DESTINATION bin OPTIONAL)
install(DIRECTORY ${CMAKE_BINARY_DIR}/engine/textures DESTINATION bin OPTIONAL)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .)
if(VULKANENGINE_BUNDLE)
# Every shared lib built from fetched deps (glfw, fmt, fastgltf and its own
# simdjson, ...) with its symlinks. libstdc++ etc. are not built here.
install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/
DESTINATION lib
USE_SOURCE_PERMISSIONS
FILES_MATCHING PATTERN "*.so*"
)
endif()

View File

@ -5,20 +5,3 @@ Might expending it later into a game or engine.
Based from [vkguide](https://vkguide.dev/) Based from [vkguide](https://vkguide.dev/)
This has a very different philosophy than the main [Khronos Vulkan Tutorial](https://docs.vulkan.org/tutorial/latest/00_Introduction.html) This has a very different philosophy than the main [Khronos Vulkan Tutorial](https://docs.vulkan.org/tutorial/latest/00_Introduction.html)
## Install
You can build it yourself, using two methods:
1- Use a devenv, and cmake
2- Use nix build
Or you can grab an artefact from the actions tab (currently broken).
## Usage
All runtime documentation is included in the program, just launch it witout any arguments, or with the `-h` flag to see how to use it.
## Known bugs
Currently, when opening a new build, the imgui layout is not done, you need to dock everything yourself, only at the first launch (after that, the layout is saved in `imgui.ini`)
You also need to launch the executable in the same folder as the assets (shaders, models, textures).
All of these "bugs" are planned to be fixed.

View File

@ -1,11 +0,0 @@
# Roadmap
Finish vkguide.dev
Rewrite some part, for structure purposes
Configure offscreen rendering for imgui (docked viewport)
Separate tooling and core, for shipping
- #ifdef DEBUG for tools
- #ifdef NDEBUG for release

Binary file not shown.

58
flake.lock generated
View File

@ -1,58 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1791366222,
"narHash": "sha256-/4ezBOv6aldGab7qTb6ls3SDpgzG8kuuSqEAA9zEZ8E=",
"rev": "39ad350a0602fa0a58a544344e3e9187526ea45c",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1087089.39ad350a0602/nixexprs.tar.zst"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

114
flake.nix
View File

@ -1,114 +0,0 @@
{
description = "VulkanEngine development environment";
inputs = {
nixpkgs.url = "nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
};
vulkanPackages = with pkgs; [
vulkan-headers
vulkan-loader
vulkan-validation-layers
vulkan-tools
vulkan-utility-libraries
vulkan-memory-allocator
vulkan-volk
vk-bootstrap
];
developmentPackages = with pkgs; [
# Shaders
shader-slang
glslang
# Vulkan
vulkan-headers
vulkan-loader
vulkan-validation-layers
vulkan-tools
vulkan-utility-libraries
vulkan-memory-allocator
vulkan-volk
vk-bootstrap
# Windowing
glfw3
wayland
wayland-protocols
wayland-scanner
libxkbcommon
# Audio
libpulseaudio
libpulseaudio.dev
# Libraries
fmt
cli11
simdjson
glm
nlohmann_json
tinyobjloader
tinygltf
stb
# Build
cmake
ninja
pkg-config
# Debug
gdb
renderdoc
];
in {
devShells.default = pkgs.mkShell {
name = "vulkan-engine";
hardeningDisable = [
"fortify"
];
packages = developmentPackages;
VK_LAYER_PATH =
"${pkgs.vulkan-validation-layers}/share/vulkan/explicit_layer.d";
VULKAN_SDK =
"${pkgs.vulkan-validation-layers}";
shellHook = ''
export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath [
pkgs.vulkan-loader
pkgs.wayland
pkgs.libxkbcommon
]}"
echo "VulkanEngine development environment"
echo "CMake: $(cmake --version | head -n1)"
echo "Ninja: $(ninja --version)"
echo "GCC: $(g++ --version | head -n1)"
echo "GLSLang: $(glslangValidator --version | head -n1)"
echo "Slang: $(slangc -v | head -n1)"
unset SOURCE_DATE_EPOCH
'';
};
packages.engine =
pkgs.callPackage ./package.nix {};
packages.default =
self.packages.${system}.engine;
}
);
}

@ -1 +0,0 @@
Subproject commit c1cfe00d2f3d862aecfe6e69ec810414d5f4c906

@ -1 +0,0 @@
Subproject commit d7cce3ad5070bbdbbd7a39335c0c1e90071211d0

View File

@ -1,117 +0,0 @@
{ lib
, stdenv
, fetchFromGitHub
, fetchgit
, cmake
, ninja
, pkg-config
, glfw3
, glm
, vulkan-headers
, vulkan-loader
, vulkan-volk
, vulkan-utility-libraries
, vulkan-memory-allocator
, vk-bootstrap
, fmt
, cli11
, glslang
, shader-slang
, simdjson
, patchelf
}:
let
fs = lib.fileset;
fastgltf = fetchFromGitHub {
owner = "spnda";
repo = "fastgltf";
rev = "v0.8.0";
hash = "sha256-nPkVMrve1+04XRpSswBqjlSurliCFBRxR8Zxy4xZ5pE=";
};
imgui = fetchgit {
url = "https://git.alexdelcamp.fr/Alexandre_1a/imgui.git";
rev = "d7cce3ad5070bbdbbd7a39335c0c1e90071211d0";
hash = "sha256-2v085YFc17aj96YlOc4Fp8sJUHUmjRU8X54FnuqKrgc=";
};
in
stdenv.mkDerivation {
pname = "vulkan-engine";
version = "1.1.0";
src = ./.;
postUnpack = ''
# include/ peut ne pas exister du tout dans la copie flake
# (cas de figure ici), donc on le crée.
mkdir -p $sourceRoot/include
# On remplace les dossiers vides (ou absents) par les vraies sources
rm -rf $sourceRoot/include/imgui $sourceRoot/include/CLI11
cp -r ${imgui} $sourceRoot/include/imgui
# Autorise le write sur l'arbre : CMake va générer des fichiers
chmod -R u+w $sourceRoot
'';
nativeBuildInputs = [
cmake
ninja
pkg-config
glslang
shader-slang
];
buildInputs = [
glfw3
glm
vulkan-headers
vulkan-volk
vulkan-loader
vulkan-utility-libraries
vk-bootstrap
vulkan-memory-allocator
fmt
cli11
simdjson
];
cmakeFlags = [
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
"-DFETCHCONTENT_SOURCE_DIR_FASTGLTF=${fastgltf}"
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
];
postFixup = ''
patchelf --add-rpath ${lib.makeLibraryPath [ vulkan-loader ]} $out/bin/engine
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp engine/engine $out/bin/engine
cp server/server $out/bin/server
# Copier les shaders compilés où qu'ils soient
if [ -d engine/shaders ]; then
cp -r engine/shaders $out/bin/shaders
elif [ -d $sourceRoot/engine/shaders ]; then
# fallback : sources, à compiler ? normalement non
cp -r $sourceRoot/engine/shaders $out/bin/shaders
else
echo "ERREUR : aucun dossier shaders trouvé" >&2
find . -name "*.spv" >&2
exit 1
fi
[ -d engine/models ] && cp -r engine/models $out/bin/models
[ -d engine/textures ] && cp -r engine/textures $out/bin/textures
[ -f engine/LICENSE ] && cp engine/LICENSE $out/bin/LICENSE
runHook postInstall
'';
meta.mainProgram = "engine";
}

View File

@ -0,0 +1,30 @@
static float2 positions[3] = float2[](
float2(0.0, -0.5),
float2(0.5, 0.5),
float2(-0.5, 0.5)
);
static float3 colors[3] = float3[] (
float3(1.0, 0.0, 0.0),
float3(0.0, 1.0, 0.0),
float3(0.0, 0.0, 1.0)
);
struct VertexOutput {
float3 color;
float4 sv_position : SV_Position;
};
[shader("vertex")]
VertexOutput vertMain(uint vid : SV_VertexID) {
VertexOutput output;
output.sv_position = float4(positions[vid], 0.0, 1.0);
output.color = colors[vid];
return output;
}
[shader("fragment")]
float4 fragMain(VertexOutput inVert) : SV_Target {
float3 color = inVert.color;
return float4(color, 1.0);
}

View File

@ -1,13 +0,0 @@
#version 450
//shader input
layout(location = 0) in vec3 inColor;
//output write
layout(location = 0) out vec4 outFragColor;
void main()
{
//return red
outFragColor = vec4(inColor, 1.0f);
}

View File

@ -1,36 +0,0 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(location = 0) out vec3 outColor;
layout(location = 1) out vec2 outUV;
struct Vertex {
vec3 position;
float uv_x;
vec3 normal;
float uv_y;
vec4 color;
};
layout(buffer_reference, std430) readonly buffer VertexBuffer {
Vertex vertices[];
};
//push constants block
layout(push_constant) uniform constants
{
mat4 render_matrix;
VertexBuffer vertexBuffer;
} PushConstants;
void main()
{
//load vertex data from device adress
Vertex v = PushConstants.vertexBuffer.vertices[gl_VertexIndex];
//output data
gl_Position = PushConstants.render_matrix * vec4(v.position, 1.0f);
outColor = v.color.xyz;
outUV.x = v.uv_x;
outUV.y = v.uv_y;
}

View File

@ -1,24 +0,0 @@
#version 450
layout (location = 0) out vec3 outColor;
void main()
{
//const array of positions for the triangle
const vec3 positions[3] = vec3[3](
vec3(1.f,1.f, 0.0f),
vec3(-1.f,1.f, 0.0f),
vec3(0.f,-1.f, 0.0f)
);
//const array of colors for the triangle
const vec3 colors[3] = vec3[3](
vec3(1.0f, 0.0f, 0.0f), //red
vec3(0.0f, 1.0f, 0.0f), //green
vec3(00.f, 0.0f, 1.0f) //blue
);
//output the position of each vertex
gl_Position = vec4(positions[gl_VertexIndex], 1.0f);
outColor = colors[gl_VertexIndex];
}

View File

@ -1,31 +1,8 @@
/*
Todo:
The timestamp is not in localtime,
fix or disclaim
*/
#ifndef LOGGER_H #ifndef LOGGER_H
#define LOGGER_H #define LOGGER_H
// Custom includes // Custom includes
// Enums
enum class LogModule {
ENGINE,
RENDERER,
GLFW,
CLEANUP
};
enum class LogLevel {
EDEBUG,
EINIT, // Initialization related
EINFO, // General infos
EWARN,
EERROR,
EFATAL
};
class NetLogger { class NetLogger {
public: public:
struct Server{ struct Server{
@ -40,79 +17,7 @@ class NetLogger {
void logNetAsync(); // Todo void logNetAsync(); // Todo
private: private:
};
class Logger {
public:
// Members
std::string logBuffer; // Log is empty by default
std::vector<std::string_view> lines;
// Functions
template<typename... Args>
void logDisk(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to a file on disk
// Overload
void logDisk(std::string_view message);
template<typename... Args>
void logRAM(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to ram (ImGUI)
template<typename... Args>
void logConsole(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to the console (crashes, etc...)
template<typename... Args>
void logAll(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs using all of the above, RAM then console and finally disk, maybe multithread (?)
template<typename... Args>
void logImportant(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
); // Logs to console and file, in cases of crashes or errors
template<typename... Args>
void logFatal(
LogModule module,
std::string_view message,
Args&&... args
); // Logs to console and file, then abort -> Core dump
// Utils functions
void merge(std::string_view source); // Merges a source dumped logs into this
void logSeparator();
void clear();
private:
// Helper functions
static std::string_view moduleToString(LogModule m);
static std::string_view levelToString(LogLevel l);
inline std::string formatTimestamp(
std::chrono::system_clock::time_point tp
);
}; };
#endif // End of header #endif // End of header
@ -124,271 +29,12 @@ class Logger {
// Implementation // Implementation
// Includes // Includes
//#include <httplib.h> // Todo : add it in the flake #include <httplib.h> // Todo : add it in the flake
#include <iostream>
#include <fstream>
#include <chrono>
/*
void NetLogger::initNetLogger(Server server) { void NetLogger::initNetLogger(Server server) {
httplib::Client cli(server.url) httplib::Client cli(server.url)
// Todo : add error handling // Todo : add error handling
} }
*/
template<typename... Args>
void Logger::logRAM(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
auto now { std::chrono::system_clock::now() };
auto timestamp = formatTimestamp(now);
auto start = logBuffer.size();
fmt::format_to(
std::back_inserter(logBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(logBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(logBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
logBuffer.push_back('\n');
auto end = logBuffer.size();
lines.emplace_back(logBuffer.data() + start, end - start);
}
template<typename... Args>
void Logger::logConsole(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
std::string tempBuffer;
auto now = std::chrono::system_clock::now();
auto timestamp = formatTimestamp(now);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(tempBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
std::cout.write(tempBuffer.data(), tempBuffer.size());
std::cout.put('\n');
}
template<typename... Args>
void Logger::logDisk(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
// Open the logfile
std::ofstream logFile ("log.txt", std::ios::out | std::ios::app);
if (!logFile.good()) {
throw std::runtime_error("Failed to open logfile !");
}
// Create a temporary buffer
std::string tempBuffer;
auto now = std::chrono::system_clock::now();
auto timestamp = formatTimestamp(now);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}] ",
timestamp
);
fmt::format_to(
std::back_inserter(tempBuffer),
"[{}:{}] ",
moduleToString(module),
levelToString(level)
);
fmt::format_to(
std::back_inserter(tempBuffer),
fmt::runtime(message),
std::forward<Args>(args)...
);
logFile << tempBuffer << '\n';
logFile.close();
}
// Overload to inject a message
void Logger::logDisk(std::string_view message) {
std::ofstream logFile ("log.txt", std::ios::out | std::ios::app);
if (!logFile.good()) {
throw std::runtime_error("Failed to open logfile !");
}
logFile << message << '\n';
logFile.close();
}
template<typename... Args>
void Logger::logAll(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
// Logs to all targets !
logRAM(
module,
level,
message,
args...
);
logConsole(
module,
level,
message,
args...
);
logDisk(
module,
level,
message,
args...
);
}
template<typename... Args>
void Logger::logImportant(
LogModule module,
LogLevel level,
std::string_view message,
Args&&... args
) {
logDisk(
module,
level,
message,
args...
);
logConsole(
module,
level,
message,
args...
);
}
template<typename... Args>
void Logger::logFatal(
LogModule module,
std::string_view message,
Args&&... args
) {
// Separator
logDisk("================================== CRASH LOGS ==================================");
logDisk(
module,
LogLevel::EFATAL,
message,
args...
);
logConsole(
module,
LogLevel::EFATAL,
message,
args...
);
logSeparator();
std::abort();
}
void Logger::merge(std::string_view source) {
/*
This merges a dumped logger into this one
Assumes the other logger is already formated.
This allows to add arbitrary strings into the logs
*/
logBuffer += source;
}
void Logger::logSeparator() {
logDisk("================================================================================");
}
void Logger::clear() {
logBuffer.clear();
}
std::string_view Logger::moduleToString(LogModule m) {
using enum LogModule;
switch (m) {
case ENGINE: return "Engine";
case RENDERER: return "Renderer";
case GLFW: return "GLFW";
case CLEANUP: return "CLEANUP";
default: return "Unkown";
}
}
std::string_view Logger::levelToString(LogLevel l) {
using enum LogLevel;
switch (l) {
case EDEBUG: return "Debug";
case EINFO: return "Info";
case EINIT: return "Init";
case EWARN: return "Warn";
case EERROR: return "Error";
case EFATAL: return "Fatal";
default: return "???";
}
}
std::string Logger::formatTimestamp(
std::chrono::system_clock::time_point tp
) {
std::time_t t = std::chrono::system_clock::to_time_t(tp);
std::tm tm{};
localtime_r(&t, &tm);
return fmt::format("{:%Y-%m-%d %H:%M}", tm);
}
#endif #endif
#endif #endif

View File

@ -12,25 +12,19 @@
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <fmt/base.h> #include <fmt/base.h>
#include <fmt/format.h>
#include <fmt/chrono.h>
#include <stdexcept> #include <stdexcept>
#include <cstdint> #include <cstdint>
#include <volk.h> #include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
#include <vulkan/vk_enum_string_helper.h> #include <vulkan/vk_enum_string_helper.h>
#include <vk_mem_alloc.h> #include <vk_mem_alloc.h>
//#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#define GLM_ENABLE_EXPERIMENTAL
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_FORCE_RADIANS
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <glm/vec4.hpp> #include <glm/vec4.hpp>
#include <glm/gtx/transform.hpp>
// Custom headers // Custom headers
//#include "callbacks.h" //#include "callbacks.h"
@ -47,16 +41,9 @@
} \ } \
} while (0) \ } while (0) \
// Enums
enum class RenderRez {
FIT,
R800x800,
R720p,
R1080p,
R2k
};
// Custom types // Custom types
struct DeletionQueue { struct DeletionQueue {
std::deque<std::function<void()>> deletors; std::deque<std::function<void()>> deletors;
@ -87,42 +74,6 @@ struct AllocatedImage {
VkFormat imageFormat; VkFormat imageFormat;
}; };
struct AllocatedBuffer {
VkBuffer buffer;
VmaAllocation allocation;
VmaAllocationInfo info;
uint32_t size; // In bytes
};
struct Vertex {
alignas(16) glm::vec3 position;
float uv_x;
alignas(16) glm::vec3 normal;
float uv_y;
glm::vec4 color;
};
// Holds the ressouces required for a mesh
struct GPUMeshBuffers {
AllocatedBuffer indexBuffer;
AllocatedBuffer vertexBuffer;
VkDeviceAddress vertexBufferAddress;
};
struct GPUDrawPushConstants {
glm::mat4 worldMatrix;
VkDeviceAddress vertexBuffer;
};
// Engine config
struct EngineConfig {
int gpuIndex {-1};
std::string modelPath;
};
// "Global" ? (I hope so) logger
Logger logger;
#endif #endif

View File

@ -17,7 +17,7 @@ class Callback {
void Callback::keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { void Callback::keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
#ifdef DEBUG #ifdef DEBUG
logger.logRAM(LogModule::GLFW, LogLevel::EINFO, "Key pressed, key {}", key); fmt::println("[Engine:Info] Key pressed, key {}", key);
#endif #endif
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
#define INITIALIZERS_H #define INITIALIZERS_H
// Normal header // Normal header
#include "Common/Types.h" #include "Common/Types.h"
#include "simdjson.h"
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
namespace vkinit { namespace vkinit {
@ -65,19 +64,12 @@ namespace vkinit {
VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/ VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/
); );
VkRenderingAttachmentInfo depthAttachmentInfo(
VkImageView view,
VkImageLayout layout
);
VkRenderingInfo renderingInfo( VkRenderingInfo renderingInfo(
VkExtent2D renderExtent, VkExtent2D renderExtent,
VkRenderingAttachmentInfo* colorAttachment, VkRenderingAttachmentInfo* colorAttachment,
VkRenderingAttachmentInfo* depthAttachment VkRenderingAttachmentInfo* depthAttachment
); );
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo();
VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo( VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo(
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
VkShaderModule shaderModule, VkShaderModule shaderModule,
@ -295,27 +287,6 @@ namespace vkinit {
return colorAttachment; return colorAttachment;
} }
VkRenderingAttachmentInfo depthAttachmentInfo(
VkImageView view,
VkImageLayout layout
) {
VkRenderingAttachmentInfo depthAttachment {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = view,
.imageLayout = layout,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = {
.depthStencil = {
.depth = 0.0f
}
}
};
return depthAttachment;
}
VkRenderingInfo renderingInfo( VkRenderingInfo renderingInfo(
VkExtent2D renderExtent, VkExtent2D renderExtent,
VkRenderingAttachmentInfo* colorAttachment, VkRenderingAttachmentInfo* colorAttachment,
@ -339,21 +310,6 @@ namespace vkinit {
return renderInfo; return renderInfo;
} }
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo() {
VkPipelineLayoutCreateInfo info {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
// Empty defaults
.flags = 0,
.setLayoutCount = 0,
.pSetLayouts = nullptr,
.pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr,
};
return info;
}
VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo( VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo(
VkShaderStageFlagBits stage, VkShaderStageFlagBits stage,
VkShaderModule shaderModule, VkShaderModule shaderModule,

View File

@ -1,197 +0,0 @@
#ifndef LOADER_H
#define LOADER_H
// Header
// Custom includes
#include "Common/Types.h"
// Other includes
#include <cstdint>
#include <unordered_map>
#include <filesystem>
// Stucts
struct GeoSurface {
uint32_t startIndex;
uint32_t count;
};
struct MeshAsset {
std::string name;
std::vector<GeoSurface> surfaces;
GPUMeshBuffers meshBuffers;
};
// Forward declaration
class Engine;
#endif
#ifdef LOADER_IMPL
#ifndef LOADER_IMPL_H
#define LOADER_IMPL_H
// Main code file
// Includes
#include <fastgltf/core.hpp>
#include <fastgltf/types.hpp>
#include <fastgltf/glm_element_traits.hpp>
#include <fastgltf/tools.hpp>
constexpr bool OverrideColors = true;
std::optional<std::vector<std::shared_ptr<MeshAsset>>> loadGltfMeshes(
Engine* engine,
std::filesystem::path filePath
) {
// Todo:
// Use util functions for attributes
auto& logger = engine->_logger; // Uses the main logger
logger.logAll(LogModule::ENGINE, LogLevel::EINFO, "Loading GLTF: {}", filePath.string());
fastgltf::Parser parser;
fastgltf::Asset gltf;
auto data = fastgltf::GltfDataBuffer::FromPath(filePath);
constexpr auto gltfOptions {
fastgltf::Options::LoadExternalBuffers
};
auto load = parser.loadGltf(
data.get(),
filePath.parent_path(),
gltfOptions
);
if(load) {
gltf = std::move(load.get());
} else {
logger.logFatal(LogModule::ENGINE, "Failed to load gltf: {}", fastgltf::to_underlying(load.error()));
}
std::vector<std::shared_ptr<MeshAsset>> meshes;
// Use the same vectors for all meshes
// so that the memory doesn't reallocate
// as often
std::vector<uint32_t> indices;
std::vector<Vertex> vertices;
// Now, some gltf gymnastics to get data into the correct buffers.
/*
====================================
The following comments are notes,
to help me build the loader,
based on the new fastgltf api
(the vkguide is using an older api)
====================================
By reading the vkguide, I can see that
he's iterating on "gltf" which is an Asset.
In the official docs, it is stated we can get direct
references to the Asset class, using pointers (->)
For exemple with buffers: asset->buffers
*/
for(fastgltf::Mesh& mesh : gltf.meshes) { // Perhaps error ?
MeshAsset newmesh;
newmesh.name = mesh.name;
// Clear the arrays for memory optimizations
indices.clear();
vertices.clear();
for(auto&& p : mesh.primitives) { // 100% Error, use pointers ig ?
GeoSurface newSurface;
newSurface.startIndex = (uint32_t)indices.size();
newSurface.count = (uint32_t)gltf.accessors[p.indicesAccessor.value()].count;
size_t initialVTX = vertices.size();
// -- Indices --
{
fastgltf::Accessor& indexAccessor = gltf.accessors[p.indicesAccessor.value()];
indices.reserve(indices.size() + indexAccessor.count); // Memory alloc ig ?
fastgltf::iterateAccessor<std::uint32_t>(gltf, indexAccessor,
[&](std::uint32_t idx) {
indices.push_back(idx + initialVTX);
}
);
}
// -- Vertex Positions --
{
auto posIt = p.findAttribute("POSITION");
if (posIt == p.attributes.end()) {
logger.logFatal(LogModule::ENGINE, "Primitive without POSITION attribute");
return std::nullopt;
}
fastgltf::Accessor& posAccessor = gltf.accessors[posIt->accessorIndex];
vertices.resize(vertices.size() + posAccessor.count);
fastgltf::iterateAccessorWithIndex<glm::vec3>(gltf, posAccessor,
[&](glm::vec3 v, size_t index) {
Vertex newvtx;
newvtx.position = v;
newvtx.normal = { 1.0f, 0.0f, 0.0f };
newvtx.color = glm::vec4(1.0f);
newvtx.uv_x = 0.0f;
newvtx.uv_y = 0.0f;
vertices[initialVTX + index] = newvtx;
}
);
}
// --- Normals ---
if (auto normals = p.findAttribute("NORMAL"); normals != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec3>(gltf, gltf.accessors[normals->accessorIndex],
[&](glm::vec3 v, size_t index) {
vertices[initialVTX + index].normal = v;
}
);
}
// --- UVs ---
if (auto uv = p.findAttribute("TEXCOORD_0"); uv != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec2>(gltf, gltf.accessors[uv->accessorIndex],
[&](glm::vec2 v, size_t index) {
vertices[initialVTX + index].uv_x = v.x;
vertices[initialVTX + index].uv_y = v.y;
}
);
}
// --- Vertex Colors ---
if (auto colors = p.findAttribute("COLOR_0"); colors != p.attributes.end()) {
fastgltf::iterateAccessorWithIndex<glm::vec4>(gltf, gltf.accessors[colors->accessorIndex],
[&](glm::vec4 v, size_t index) {
vertices[initialVTX + index].color = v;
}
);
}
newmesh.surfaces.push_back(newSurface);
}
// Display vertex normals
if (OverrideColors) {
for (Vertex& vtx : vertices) {
vtx.color = glm::vec4(vtx.normal, 1.0f);
}
}
newmesh.meshBuffers = engine->uploadMesh(indices, vertices);
meshes.emplace_back(std::make_shared<MeshAsset>(std::move(newmesh)));
}
// Debug things
#ifdef DEBUG
if(fastgltf::validate(load.get()) != fastgltf::Error::None) {
logger.logFatal(LogModule::ENGINE, "gltf file is not up to spec !");
}
#endif
return meshes;
}
#endif
#endif

View File

@ -1,8 +1,3 @@
/*
Todo:
Create a temporary struct, to have the correct structure
then copy it to the class member
*/
#ifndef PIPELINES_H #ifndef PIPELINES_H
#define PIPELINES_H #define PIPELINES_H
// Normal header // Normal header
@ -33,7 +28,6 @@ class PipelineBuilder {
VkPipelineLayout _pipelineLayout; VkPipelineLayout _pipelineLayout;
VkPipelineDepthStencilStateCreateInfo _depthStencil; VkPipelineDepthStencilStateCreateInfo _depthStencil;
VkPipelineRenderingCreateInfo _renderInfo; VkPipelineRenderingCreateInfo _renderInfo;
VkFormat _colorAttachmentFormat;
PipelineBuilder() { clear(); } PipelineBuilder() { clear(); }
@ -63,9 +57,7 @@ class PipelineBuilder {
void setMultisamplingNone(); void setMultisamplingNone();
void enableBlendingAdditive(); void disableBlending ();
void enableBlendingAlphaBlend();
void disableBlending();
void setColorAttachmentFormat( void setColorAttachmentFormat(
VkFormat format VkFormat format
@ -76,10 +68,6 @@ class PipelineBuilder {
); );
void disableDepthtest(); void disableDepthtest();
void enableDepthtest(
bool depthWriteEnable,
VkCompareOp op
);
}; };
#endif #endif
@ -335,28 +323,6 @@ void PipelineBuilder::setMultisamplingNone() {
_multisampling.alphaToOneEnable = VK_FALSE; _multisampling.alphaToOneEnable = VK_FALSE;
} }
void PipelineBuilder::enableBlendingAdditive() {
_colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
_colorBlendAttachment.blendEnable = VK_TRUE;
_colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
_colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
_colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
_colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
_colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
_colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
}
void PipelineBuilder::enableBlendingAlphaBlend() {
_colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
_colorBlendAttachment.blendEnable = VK_TRUE;
_colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
_colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
_colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
_colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
_colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
_colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
}
void PipelineBuilder::disableBlending() { void PipelineBuilder::disableBlending() {
// Default write mask // Default write mask
_colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; _colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
@ -364,15 +330,6 @@ void PipelineBuilder::disableBlending() {
_colorBlendAttachment.blendEnable = VK_FALSE; _colorBlendAttachment.blendEnable = VK_FALSE;
} }
void PipelineBuilder::setColorAttachmentFormat(
VkFormat format
) {
_colorAttachmentFormat = format;
// connect the format to the renderInfo structure
_renderInfo.colorAttachmentCount = 1;
_renderInfo.pColorAttachmentFormats = &_colorAttachmentFormat;
}
void PipelineBuilder::setDepthFormat( void PipelineBuilder::setDepthFormat(
VkFormat format VkFormat format
) { ) {
@ -391,20 +348,5 @@ void PipelineBuilder::disableDepthtest() {
_depthStencil.maxDepthBounds = 1.0f; _depthStencil.maxDepthBounds = 1.0f;
} }
void PipelineBuilder::enableDepthtest(
bool depthWriteEnable,
VkCompareOp op
) {
_depthStencil.depthTestEnable = VK_TRUE;
_depthStencil.depthWriteEnable = depthWriteEnable;
_depthStencil.depthCompareOp = op;
_depthStencil.depthBoundsTestEnable = VK_FALSE;
_depthStencil.stencilTestEnable = VK_FALSE;
_depthStencil.front = {};
_depthStencil.back = {};
_depthStencil.minDepthBounds = 0.0f;
_depthStencil.maxDepthBounds = 1.0f;
}
#endif #endif
#endif #endif

View File

@ -1,99 +1,18 @@
/*
Copyright Alexandre Delcamp-Enache, 2026
Based on vkguide.dev
See engine.h for extensive documentation
Also, checkout the roadmap
*/
#define ENGINE_IMPL #define ENGINE_IMPL
#include "engine/engine.h" #include "engine/engine.h"
#include "CLI/CLI.hpp"
class ArgHandler {
public:
CLI::App* _run;
// All options
bool _listGPU {false};
EngineConfig config;
void buildArgs() {
// Setup
// Subcommands
_run = _app.add_subcommand("run");
// Main options/flags
_app.add_flag("--list-gpu, -l", _listGPU, "Lists available Graphics cards, useful for debugging");
_app.set_version_flag("--version, -v", BUILD_ID);
// Help
//_app.set_help_all_flag("--help-all", "Expand all help");
_app.set_help_flag();
_app.set_help_all_flag("--help, -h", "Print help for all subcommands");
// Subcommand options/flags
// Run
_run->add_option("--gpu, -g", config.gpuIndex, "Manually select a GPU");
_run->add_option("--model, -m", config.modelPath, "Overwrites the default model");
}
int dispatch(int argc, char* argv[]) {
CLI11_PARSE(_app, argc, argv);
return 0;
}
void printHelp() {
fmt::println("{}", _app.help());
}
private:
CLI::App _app;
};
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Classes we need
Engine engine; Engine engine;
ArgHandler handler;
// Exemple of overwriting a class value // Exemple of overwriting a class value
//engine._windowExtent = { 67, 67 }; //engine._windowExtent = { 67, 67 };
handler.buildArgs(); engine.init();
if (argc == 1) { engine.run();
handler.printHelp();
fmt::println("Please use -h or --help to see all available options.");
return 0;
}
// Checks for -h flag engine.cleanup();
int result = handler.dispatch(argc, argv);
if(result != 0) return result;
if (handler._run->parsed() &&
handler._run->get_help_ptr()->as<bool>()) {
return 0;
}
if(handler._listGPU) {
engine.getAvailableGPU();
return 0;
}
if(handler._run->parsed()){
engine.parseConfig(
handler.config
);
engine.init();
engine.run();
engine.cleanup();
}
return 0; return 0;
} }

1
src/imgui Submodule

@ -0,0 +1 @@
Subproject commit b48d1afbe8ee8b238e2961dc363a949dd7304e23