Compare commits
72 Commits
c246da98ff
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba47255ee0 | ||
|
|
8690efe184 | ||
|
|
d6445092c2 | ||
|
|
452bf92e20 | ||
|
|
6c2f580134 | ||
|
|
d58b84d4a5 | ||
|
|
19a3e55e5f | ||
|
|
fe9ecb1ecc | ||
|
|
de7cbdc73c | ||
|
|
82b499e65c | ||
|
|
4ab4ea5262 | ||
|
|
f86e1b872a | ||
|
|
72c7db8439 | ||
|
|
1c8a6840e6 | ||
|
|
7426374b00 | ||
|
|
a3bb54f041 | ||
|
|
bb75a3400a | ||
|
|
5e580af16f | ||
|
|
c755d39677 | ||
|
|
cdc6a1f92c | ||
|
|
64671363dc | ||
|
|
a5643d794c | ||
|
|
89435a66a4 | ||
|
|
97f8e71e18 | ||
|
|
12c617587f | ||
|
|
a278ce14c5 | ||
|
|
ecc3f595bc | ||
|
|
d4dbcc85fb | ||
|
|
befd8b3cd9 | ||
|
|
dedc37f6ac | ||
|
|
a1936d666c | ||
|
|
a5a97d141e | ||
|
|
01e74fe40e | ||
|
|
1923da2339 | ||
|
|
f6096e2889 | ||
|
|
b879f2a636 | ||
|
|
023016c6a2 | ||
|
|
6ee58d4901 | ||
|
|
bb29a1d3f1 | ||
|
|
c6d1fd8910 | ||
|
|
7d9b31fe12 | ||
|
|
4ce6791343 | ||
|
|
9bce759259 | ||
|
|
c82fc49aac | ||
|
|
5d1da184e0 | ||
|
|
1a2b6ae364 | ||
|
|
5262143af8 | ||
|
|
a1c6ffa0b7 | ||
|
|
7d1774e222 | ||
|
|
92e3092d3b | ||
|
|
ef72cb56c6 | ||
|
|
6e4863961d | ||
|
|
6b011860fc | ||
|
|
86e15013d0 | ||
|
|
0b2f7ba60f | ||
|
|
cfe51648bd | ||
|
|
96d2e89d48 | ||
|
|
eeb7c9c00f | ||
|
|
6e37fda356 | ||
|
|
c1732e01fa | ||
|
|
484fe4aa3e | ||
|
|
eedee9dd9f | ||
|
|
474874d21b | ||
|
|
30c9683780 | ||
|
|
2088dde6ca | ||
|
|
081a091f37 | ||
|
|
8ae128e0ee | ||
|
|
4ada346252 | ||
|
|
7c7ac67fc8 | ||
|
|
a7c2e586eb | ||
|
|
d45bd62623 | ||
| 760b619f9e |
8
.gitignore
vendored
@ -1,7 +1,13 @@
|
|||||||
# ---> C++
|
# ---> C++
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
|
cmake-build-*/
|
||||||
|
.idea/
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
build/
|
||||||
# Compiled Object files
|
# Compiled Object files
|
||||||
*.slo
|
*.slo
|
||||||
*.lo
|
*.lo
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "external/NetworkCore"]
|
||||||
|
path = external/NetworkCore
|
||||||
|
url = git@git.fawkes100.de:sebastian/JsonTCPServer.git
|
||||||
@ -1,8 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="CPP_MODULE" version="4">
|
<module classpath="CIDR" type="CPP_MODULE" version="4" />
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
356
CMakeLists.txt
@ -1,6 +1,358 @@
|
|||||||
cmake_minimum_required(VERSION 4.2)
|
cmake_minimum_required(VERSION 4.2)
|
||||||
project(ColorRace)
|
project(ColorRace)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
add_executable(ColorRace main.cpp)
|
# --- CPM.cmake Bootstrap ---
|
||||||
|
set(CPM_DOWNLOAD_VERSION 0.40.2)
|
||||||
|
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||||
|
if(NOT EXISTS ${CPM_DOWNLOAD_LOCATION})
|
||||||
|
file(DOWNLOAD
|
||||||
|
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
|
||||||
|
${CPM_DOWNLOAD_LOCATION}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
include(${CPM_DOWNLOAD_LOCATION})
|
||||||
|
|
||||||
|
# --- OpenGL (systemseitig, kein CPM nötig) ---
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
# --- GLFW ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME glfw
|
||||||
|
GITHUB_REPOSITORY glfw/glfw
|
||||||
|
GIT_TAG 3.4
|
||||||
|
OPTIONS
|
||||||
|
"GLFW_BUILD_EXAMPLES OFF"
|
||||||
|
"GLFW_BUILD_TESTS OFF"
|
||||||
|
"GLFW_BUILD_DOCS OFF"
|
||||||
|
"GLFW_INSTALL OFF"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- GLM (header-only) ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME glm
|
||||||
|
GITHUB_REPOSITORY g-truc/glm
|
||||||
|
GIT_TAG 1.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- tinyobjloader ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME tinyobjloader
|
||||||
|
GITHUB_REPOSITORY tinyobjloader/tinyobjloader
|
||||||
|
GIT_TAG v2.0.0rc13
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- stb_image (kein CMake-Projekt, nur Header) ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME stb
|
||||||
|
GITHUB_REPOSITORY nothings/stb
|
||||||
|
GIT_TAG master
|
||||||
|
DOWNLOAD_ONLY YES
|
||||||
|
)
|
||||||
|
add_library(stb_image STATIC third_party/stb_image_impl.cpp)
|
||||||
|
target_include_directories(stb_image PUBLIC ${stb_SOURCE_DIR})
|
||||||
|
|
||||||
|
# --- Dear ImGui (Core + GLFW/OpenGL3 Backend) ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME imgui
|
||||||
|
GITHUB_REPOSITORY ocornut/imgui
|
||||||
|
GIT_TAG v1.91.5
|
||||||
|
DOWNLOAD_ONLY YES
|
||||||
|
)
|
||||||
|
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME spdlog
|
||||||
|
GITHUB_REPOSITORY gabime/spdlog
|
||||||
|
GIT_TAG v1.15.3
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- GoogleTest ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME googletest
|
||||||
|
GITHUB_REPOSITORY google/googletest
|
||||||
|
GIT_TAG v1.15.2
|
||||||
|
OPTIONS
|
||||||
|
"INSTALL_GTEST OFF"
|
||||||
|
"gtest_force_shared_crt ON"
|
||||||
|
)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
add_library(imgui STATIC
|
||||||
|
${imgui_SOURCE_DIR}/imgui.cpp
|
||||||
|
${imgui_SOURCE_DIR}/imgui_draw.cpp
|
||||||
|
${imgui_SOURCE_DIR}/imgui_tables.cpp
|
||||||
|
${imgui_SOURCE_DIR}/imgui_widgets.cpp
|
||||||
|
${imgui_SOURCE_DIR}/imgui_demo.cpp
|
||||||
|
${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp
|
||||||
|
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR} ${imgui_SOURCE_DIR}/backends)
|
||||||
|
target_link_libraries(imgui PUBLIC glfw glad)
|
||||||
|
|
||||||
|
# --- GLAD (manuell generiert, siehe README/Hinweis unten) ---
|
||||||
|
add_library(glad STATIC third_party/glad/src/glad.c)
|
||||||
|
target_include_directories(glad PUBLIC third_party/glad/include)
|
||||||
|
|
||||||
|
# --- OpenAL-Soft ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME openal-soft
|
||||||
|
GITHUB_REPOSITORY kcat/openal-soft
|
||||||
|
GIT_TAG 1.24.3
|
||||||
|
OPTIONS
|
||||||
|
"LIBTYPE STATIC"
|
||||||
|
"ALSOFT_UTILS OFF"
|
||||||
|
"ALSOFT_EXAMPLES OFF"
|
||||||
|
"ALSOFT_TESTS OFF"
|
||||||
|
"ALSOFT_INSTALL OFF"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- dr_libs (dr_wav.h, dr_mp3.h – header-only) ---
|
||||||
|
CPMAddPackage(
|
||||||
|
NAME dr_libs
|
||||||
|
GITHUB_REPOSITORY mackron/dr_libs
|
||||||
|
GIT_TAG master
|
||||||
|
DOWNLOAD_ONLY YES
|
||||||
|
)
|
||||||
|
|
||||||
|
message(STATUS "dr_libs_SOURCE_DIR = ${dr_libs_SOURCE_DIR}")
|
||||||
|
|
||||||
|
add_subdirectory(external/NetworkCore)
|
||||||
|
|
||||||
|
# Engine als statische Lib
|
||||||
|
add_library(Engine STATIC
|
||||||
|
engine/src/core/Window.h
|
||||||
|
engine/src/core/Window.cpp
|
||||||
|
engine/src/core/Application.cpp
|
||||||
|
engine/src/core/Application.h
|
||||||
|
engine/src/core/EngineConfig.h
|
||||||
|
engine/src/utils/openglWrapper/GLStateCache.cpp
|
||||||
|
engine/src/utils/openglWrapper/GLStateCache.h
|
||||||
|
engine/src/utils/openglWrapper/GLRenderState.cpp
|
||||||
|
engine/src/utils/openglWrapper/GLRenderState.h
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Attribute.cpp
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Attribute.h
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Vbo.cpp
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Vbo.h
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Vao.cpp
|
||||||
|
engine/src/utils/openglWrapper/openglObjects/Vao.h
|
||||||
|
engine/src/utils/openglWrapper/shader/ShaderProgram.cpp
|
||||||
|
engine/src/utils/openglWrapper/shader/ShaderProgram.h
|
||||||
|
engine/src/renderer/primitives/SphereFactory.cpp
|
||||||
|
engine/src/renderer/primitives/SphereFactory.h
|
||||||
|
engine/src/utils/openglWrapper/shader/Uniform.cpp
|
||||||
|
engine/src/utils/openglWrapper/shader/Uniform.h
|
||||||
|
engine/src/utils/openglWrapper/shader/UniformValue.cpp
|
||||||
|
engine/src/utils/openglWrapper/shader/UniformValue.h
|
||||||
|
engine/src/layer/Scene.cpp
|
||||||
|
engine/src/layer/Scene.h
|
||||||
|
engine/src/loader/AssetLoader.cpp
|
||||||
|
engine/src/loader/AssetLoader.h
|
||||||
|
engine/src/loader/assets/AssetTypes.h
|
||||||
|
engine/src/loader/assets/AssetRequests.h
|
||||||
|
engine/src/loader/assets/AssetRequests.cpp
|
||||||
|
engine/src/loader/assets/RawAssetData.h
|
||||||
|
engine/src/loader/assets/AssetFormatters.h
|
||||||
|
engine/src/loader/textures/TextureUploader.cpp
|
||||||
|
engine/src/loader/textures/TextureUploader.h
|
||||||
|
engine/src/loader/textures/TextureImporter.cpp
|
||||||
|
engine/src/loader/textures/TextureImporter.h
|
||||||
|
engine/src/loader/textures/Texture2D.cpp
|
||||||
|
engine/src/loader/textures/Texture2D.h
|
||||||
|
engine/src/loader/models/ModelImporter.cpp
|
||||||
|
engine/src/loader/models/ModelImporter.h
|
||||||
|
engine/src/loader/models/ModelUploader.cpp
|
||||||
|
engine/src/loader/models/ModelUploader.h
|
||||||
|
engine/src/loader/models/Material.cpp
|
||||||
|
engine/src/loader/models/Material.h
|
||||||
|
engine/src/loader/assets/LoadedAssets.h
|
||||||
|
engine/src/loader/models/Model.cpp
|
||||||
|
engine/src/loader/models/Model.h
|
||||||
|
engine/src/loader/models/MeshSection.cpp
|
||||||
|
engine/src/loader/models/MeshSection.h
|
||||||
|
engine/src/loader/assets/AssetManager.cpp
|
||||||
|
engine/src/loader/assets/AssetManager.h
|
||||||
|
engine/src/renderer/entities/PointLight.cpp
|
||||||
|
engine/src/renderer/entities/PointLight.h
|
||||||
|
engine/src/core/inputsOutputs/inputs/MouseButton.h
|
||||||
|
engine/src/core/inputsOutputs/inputs/Mouse.cpp
|
||||||
|
engine/src/core/inputsOutputs/inputs/Mouse.h
|
||||||
|
engine/src/core/inputsOutputs/inputs/Keyboard.cpp
|
||||||
|
engine/src/core/inputsOutputs/inputs/Keyboard.h
|
||||||
|
engine/src/core/inputsOutputs/context/InputContextStack.cpp
|
||||||
|
engine/src/core/inputsOutputs/context/InputContextStack.h
|
||||||
|
engine/src/core/inputsOutputs/controller/CameraController.cpp
|
||||||
|
engine/src/core/inputsOutputs/controller/CameraController.h
|
||||||
|
engine/src/game/GameState.cpp
|
||||||
|
engine/src/game/GameState.h
|
||||||
|
engine/src/game/GameMode.cpp
|
||||||
|
engine/src/game/GameMode.h
|
||||||
|
engine/src/game/TurnBasedGameMode.cpp
|
||||||
|
engine/src/game/TurnBasedGameMode.h
|
||||||
|
engine/src/ecs/standardComponents/PickableComponent.h
|
||||||
|
engine/src/ecs/systems/PickingSystem.cpp
|
||||||
|
engine/src/ecs/systems/PickingSystem.h
|
||||||
|
engine/src/ui/ImGuiContext.cpp
|
||||||
|
engine/src/ui/ImGuiContext.h
|
||||||
|
engine/src/renderer/shader/BoundingDebugShader.cpp
|
||||||
|
engine/src/renderer/shader/BoundingDebugShader.h
|
||||||
|
engine/src/renderer/DebugRenderer.cpp
|
||||||
|
engine/src/renderer/DebugRenderer.h
|
||||||
|
engine/src/layer/DebugLayer.cpp
|
||||||
|
engine/src/layer/DebugLayer.h
|
||||||
|
engine/src/loader/models/AABB.cpp
|
||||||
|
engine/src/loader/models/AABB.h
|
||||||
|
engine/src/loader/models/Ray.h
|
||||||
|
engine/src/ecs/standardComponents/HighlightComponent.h
|
||||||
|
third_party/audio_impl.cpp
|
||||||
|
engine/src/core/audio/AudioDevice.cpp
|
||||||
|
engine/src/core/audio/AudioDevice.h
|
||||||
|
engine/src/core/audio/SoundBuffer.cpp
|
||||||
|
engine/src/core/audio/SoundBuffer.h
|
||||||
|
engine/src/core/audio/SoundSource.cpp
|
||||||
|
engine/src/core/audio/SoundSource.h
|
||||||
|
engine/src/loader/sounds/SoundUploader.cpp
|
||||||
|
engine/src/loader/sounds/SoundUploader.h
|
||||||
|
engine/src/core/animation/components/TransformAnimationComponent.h
|
||||||
|
engine/src/core/animation/AnimationSystem.cpp
|
||||||
|
engine/src/core/animation/AnimationSystem.h
|
||||||
|
engine/src/renderer/shader/StaticShader.cpp
|
||||||
|
engine/src/renderer/shader/StaticShader.h
|
||||||
|
engine/src/renderer/entities/Camera.cpp
|
||||||
|
engine/src/renderer/entities/Camera.h
|
||||||
|
engine/src/ecs/EntityRegistry.cpp
|
||||||
|
engine/src/ecs/EntityRegistry.h
|
||||||
|
engine/src/ecs/Entity.cpp
|
||||||
|
engine/src/ecs/Entity.h
|
||||||
|
engine/src/ecs/ComponentPool.cpp
|
||||||
|
engine/src/ecs/ComponentPool.h
|
||||||
|
engine/src/ecs/standardComponents/TransformComponent.h
|
||||||
|
engine/src/ecs/standardComponents/MeshComponent.h
|
||||||
|
engine/src/ecs/EntitySystem.cpp
|
||||||
|
engine/src/ecs/EntitySystem.h
|
||||||
|
engine/src/renderer/RenderSystem.cpp
|
||||||
|
engine/src/renderer/RenderSystem.h
|
||||||
|
engine/src/renderer/RenderQueue.cpp
|
||||||
|
engine/src/renderer/RenderQueue.h
|
||||||
|
engine/src/renderer/MeshRenderSystem.cpp
|
||||||
|
engine/src/renderer/MeshRenderSystem.h
|
||||||
|
engine/src/renderer/MeshRenderer.cpp
|
||||||
|
engine/src/renderer/MeshRenderer.h
|
||||||
|
engine/src/layer/Layer.cpp
|
||||||
|
engine/src/layer/Layer.h
|
||||||
|
engine/src/core/inputsOutputs/context/InputContext.cpp
|
||||||
|
engine/src/core/inputsOutputs/context/InputContext.h
|
||||||
|
engine/src/layer/SceneManager.cpp
|
||||||
|
engine/src/layer/SceneManager.h
|
||||||
|
engine/src/core/events/EventBus.cpp
|
||||||
|
engine/src/core/events/EventBus.h
|
||||||
|
engine/src/core/audio/ecs/PlaySoundComponent.h
|
||||||
|
engine/src/core/animation/events/AnimationMarkerEvent.h
|
||||||
|
engine/src/core/animation/components/BlockingAnimationComponent.h
|
||||||
|
engine/src/core/audio/ecs/AudioSystem.cpp
|
||||||
|
engine/src/core/audio/ecs/AudioSystem.h
|
||||||
|
engine/src/core/audio/ecs/BlockingSoundComponent.h
|
||||||
|
engine/src/renderer/shader/GuiShader.cpp
|
||||||
|
engine/src/renderer/shader/GuiShader.h
|
||||||
|
engine/src/renderer/primitives/QuadFactory.cpp
|
||||||
|
engine/src/renderer/primitives/QuadFactory.h
|
||||||
|
engine/src/loader/models/SimpleTexturedMesh.cpp
|
||||||
|
engine/src/loader/models/SimpleTexturedMesh.h
|
||||||
|
engine/src/loader/models/Mesh.cpp
|
||||||
|
engine/src/loader/models/Mesh.h
|
||||||
|
engine/src/renderer/GuiRenderer.cpp
|
||||||
|
engine/src/renderer/GuiRenderer.h
|
||||||
|
engine/src/renderer/ui/GUITexture.cpp
|
||||||
|
engine/src/renderer/ui/GUITexture.h
|
||||||
|
engine/src/core/events/ApplicationEvents.h
|
||||||
|
engine/src/core/events/EventChannels.cpp
|
||||||
|
engine/src/core/events/EventChannels.h
|
||||||
|
engine/src/core/events/ApplicationEvents.cpp
|
||||||
|
)
|
||||||
|
target_include_directories(Engine PUBLIC engine/src ${dr_libs_SOURCE_DIR})
|
||||||
|
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image OpenAL::OpenAL NetworkCore)
|
||||||
|
|
||||||
|
# --- GameLib: Spiel-Logik, unabhängig von main.cpp testbar ---
|
||||||
|
add_library(GameLib STATIC
|
||||||
|
game/src/ColorRaceApp.cpp
|
||||||
|
game/src/ColorRaceApp.h
|
||||||
|
game/src/gameLayer/GameLayer.cpp
|
||||||
|
game/src/gameLayer/GameLayer.h
|
||||||
|
game/src/GameScene.cpp
|
||||||
|
game/src/GameScene.h
|
||||||
|
game/src/ludo/LudoGameState.cpp
|
||||||
|
game/src/ludo/LudoGameState.h
|
||||||
|
game/src/ludo/LudoTypes.h
|
||||||
|
game/src/ludo/LudoGameMode.cpp
|
||||||
|
game/src/ludo/LudoGameMode.h
|
||||||
|
game/src/ludo/BoardLayout.cpp
|
||||||
|
game/src/ludo/BoardLayout.h
|
||||||
|
game/src/ludo/PiecePresenter.cpp
|
||||||
|
game/src/ludo/PiecePresenter.h
|
||||||
|
game/src/ludo/LudoAiController.cpp
|
||||||
|
game/src/ludo/LudoAiController.h
|
||||||
|
game/src/ludo/ecs/highlight/HighlightSystem.cpp
|
||||||
|
game/src/ludo/ecs/highlight/HighlightSystem.h
|
||||||
|
game/src/AudioLayer.cpp
|
||||||
|
game/src/AudioLayer.h
|
||||||
|
game/src/ludo/DiceSource.cpp
|
||||||
|
game/src/ludo/DiceSource.h
|
||||||
|
game/src/ludo/PresentationGameState.cpp
|
||||||
|
game/src/ludo/PresentationGameState.h
|
||||||
|
game/src/gameLayer/GameRenderer.cpp
|
||||||
|
game/src/gameLayer/GameRenderer.h
|
||||||
|
game/src/gameLayer/gameController/LudoGameController.cpp
|
||||||
|
game/src/gameLayer/gameController/LudoGameController.h
|
||||||
|
game/src/gameLayer/LudoHud.cpp
|
||||||
|
game/src/gameLayer/LudoHud.h
|
||||||
|
game/src/gameLayer/GameInput.cpp
|
||||||
|
game/src/gameLayer/GameInput.h
|
||||||
|
game/src/gameLayer/gameController/LudoGameControllerContext.h
|
||||||
|
game/src/ludo/gameMode/LudoRules.cpp
|
||||||
|
game/src/ludo/gameMode/LudoRules.h
|
||||||
|
game/src/ludo/gameMode/PiecePathBuilder.cpp
|
||||||
|
game/src/ludo/gameMode/PiecePathBuilder.h
|
||||||
|
game/src/ludo/gameMode/PathNode.h
|
||||||
|
game/src/mainMenu/MainMenuScene.cpp
|
||||||
|
game/src/mainMenu/MainMenuScene.h
|
||||||
|
)
|
||||||
|
target_include_directories(GameLib PUBLIC game/src)
|
||||||
|
target_link_libraries(GameLib PUBLIC Engine)
|
||||||
|
|
||||||
|
add_subdirectory(server)
|
||||||
|
|
||||||
|
# --- Executable ---
|
||||||
|
add_executable(ColorRace
|
||||||
|
game/src/main.cpp
|
||||||
|
game/src/mainMenu/layer/MainMenuUiLayer.cpp
|
||||||
|
game/src/mainMenu/layer/MainMenuUiLayer.h
|
||||||
|
game/src/multiplayer/LudoGameClient.cpp
|
||||||
|
game/src/multiplayer/LudoGameClient.h
|
||||||
|
game/src/multiplayer/LudoNetworkEvents.h
|
||||||
|
game/src/multiplayer/lobby/LobbyScene.cpp
|
||||||
|
game/src/multiplayer/lobby/LobbyScene.h
|
||||||
|
game/src/multiplayer/lobby/LobbyUiLayer.cpp
|
||||||
|
game/src/multiplayer/lobby/LobbyUiLayer.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(ColorRace PRIVATE
|
||||||
|
Engine
|
||||||
|
GameLib
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Tests ---
|
||||||
|
add_executable(ColorRaceTests
|
||||||
|
tests/LoduGameMode.cpp
|
||||||
|
tests/helpers/SequenceDiceSource.cpp
|
||||||
|
tests/helpers/SequenceDiceSource.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(ColorRaceTests PRIVATE
|
||||||
|
GameLib
|
||||||
|
GTest::gtest
|
||||||
|
GTest::gtest_main
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(ColorRaceTests)
|
||||||
62
assets/models/GameBoard.mtl
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'GameBoard.blend'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Background
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd gameboard_brackground.png
|
||||||
|
|
||||||
|
newmtl Blue
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_blue.png
|
||||||
|
|
||||||
|
newmtl Green
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_green.png
|
||||||
|
|
||||||
|
newmtl Material
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd track.jpg
|
||||||
|
|
||||||
|
newmtl Red
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_red.png
|
||||||
|
|
||||||
|
newmtl Yellow
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_yellow.png
|
||||||
12
assets/models/chess.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 735.817688
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_blue.png
|
||||||
12
assets/models/chess_blue.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 735.817688
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_blue.png
|
||||||
BIN
assets/models/chess_blue.png
Normal file
|
After Width: | Height: | Size: 367 B |
12
assets/models/chess_green.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 735.817688
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_green.png
|
||||||
BIN
assets/models/chess_green.png
Normal file
|
After Width: | Height: | Size: 368 B |
12
assets/models/chess_red.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 735.817688
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_red.png
|
||||||
BIN
assets/models/chess_red.png
Normal file
|
After Width: | Height: | Size: 366 B |
12
assets/models/chess_yellow.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 5.2.0 LTS MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.002
|
||||||
|
Ns 735.817688
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd chess_yellow.png
|
||||||
BIN
assets/models/chess_yellow.png
Normal file
|
After Width: | Height: | Size: 367 B |
BIN
assets/models/gameboard_brackground.png
Normal file
|
After Width: | Height: | Size: 369 B |
BIN
assets/models/track.jpg
Normal file
|
After Width: | Height: | Size: 351 KiB |
41
assets/shaders/basic.frag
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
in vec2 pass_textureCoords;
|
||||||
|
in vec3 surfaceNormal;
|
||||||
|
in vec3 worldPos;
|
||||||
|
|
||||||
|
uniform sampler2D diffuseSampler;
|
||||||
|
uniform float opacity;
|
||||||
|
uniform float shininess;
|
||||||
|
|
||||||
|
uniform vec3 lightPosition;
|
||||||
|
uniform vec3 lightColor;
|
||||||
|
uniform vec3 cameraPosition;
|
||||||
|
|
||||||
|
uniform vec3 highlightColor;
|
||||||
|
uniform float highlightIntensity;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 normal = normalize(surfaceNormal);
|
||||||
|
vec3 lightDir = normalize(lightPosition - worldPos);
|
||||||
|
vec3 camDir = normalize(cameraPosition - worldPos);
|
||||||
|
vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
|
||||||
|
vec3 ambient = 0.1 * lightColor;
|
||||||
|
|
||||||
|
float diff = max(dot(normal, lightDir) , 0.0f);
|
||||||
|
vec3 diffuse = diff * lightColor;
|
||||||
|
|
||||||
|
float spec = pow(max(dot(camDir, reflectDir), 0.0), max(shininess, 1.0f));
|
||||||
|
vec3 specular = 0.5 * spec * lightColor;
|
||||||
|
|
||||||
|
vec4 texColor = texture(diffuseSampler, pass_textureCoords);
|
||||||
|
fragColor = vec4((ambient + diffuse + specular) * texColor.rgb, texColor.a * opacity);
|
||||||
|
|
||||||
|
float intensity = clamp(highlightIntensity, 0.0, 1.0);
|
||||||
|
|
||||||
|
fragColor.rgb += highlightColor * intensity;
|
||||||
|
}
|
||||||
22
assets/shaders/basic.vert
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#version 460 core
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in vec3 normal;
|
||||||
|
layout(location = 2) in vec2 textureCoords;
|
||||||
|
|
||||||
|
uniform mat4 transformationMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
|
||||||
|
out vec2 pass_textureCoords;
|
||||||
|
out vec3 surfaceNormal;
|
||||||
|
out vec3 worldPos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 worldPosition = transformationMatrix * vec4(position, 1.0f);
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * worldPosition;
|
||||||
|
pass_textureCoords = textureCoords;
|
||||||
|
|
||||||
|
surfaceNormal = mat3(transpose(inverse(transformationMatrix))) * normal;
|
||||||
|
worldPos = worldPosition.xyz;
|
||||||
|
|
||||||
|
}
|
||||||
8
assets/shaders/bounding_debug.frag
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
uniform vec3 color;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
void main() {
|
||||||
|
fragColor = vec4(color, 1.0f);
|
||||||
|
}
|
||||||
14
assets/shaders/bounding_debug.vert
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 460 core
|
||||||
|
layout(location = 0) in vec3 position;
|
||||||
|
layout(location = 1) in vec3 normal;
|
||||||
|
layout(location = 2) in vec2 textureCoords;
|
||||||
|
|
||||||
|
uniform mat4 transformationMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 worldPosition = transformationMatrix * vec4(position, 1.0f);
|
||||||
|
gl_Position = projectionMatrix * viewMatrix * worldPosition;
|
||||||
|
|
||||||
|
}
|
||||||
11
assets/shaders/gui.frag
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
in vec2 textureCoords;
|
||||||
|
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
uniform sampler2D guiTexture;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
color = texture(guiTexture, textureCoords);
|
||||||
|
}
|
||||||
12
assets/shaders/gui.vert
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 position;
|
||||||
|
|
||||||
|
out vec2 textureCoords;
|
||||||
|
|
||||||
|
uniform mat4 transformationMatrix;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = transformationMatrix * vec4(position, 0.0, 1.0);
|
||||||
|
textureCoords = vec2((position.x + 1.0) / 2.0, (position.y + 1.0) / 2.0);
|
||||||
|
}
|
||||||
BIN
assets/sounds/407484__ruthdt98__boardgame.wav
Normal file
BIN
assets/sounds/pawn_step.wav
Normal file
BIN
assets/sounds/rolling_dice.wav
Normal file
BIN
assets/textures/main_menu_background.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/textures/multiplayer_lobby.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/textures/multiplayer_lobby_background.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
assets/textures/splash_screen.png
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
60
engine/src/core/Application.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "utils/openglWrapper/GLStateCache.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
Application::Application(const EngineConfig& config)
|
||||||
|
: m_config(config),
|
||||||
|
m_window(std::make_unique<Window>(config)),
|
||||||
|
m_inputContextStack(),
|
||||||
|
m_keyboard(*m_window),
|
||||||
|
m_mouse(*m_window),
|
||||||
|
m_sceneManager(m_inputContextStack),
|
||||||
|
m_applicationEventBus(std::make_shared<EventBus<ApplicationEvents>>()) {
|
||||||
|
m_applicationEventBus->subscribe([this](ApplicationEvents& event) {
|
||||||
|
std::visit([this](auto&& e) {
|
||||||
|
using T = std::decay_t<decltype(e)>;
|
||||||
|
if constexpr (std::is_same_v<T, QuitRequested>) {
|
||||||
|
m_window->requestWindowClose();
|
||||||
|
} else if constexpr (std::is_same_v<T, SceneSwitchRequested>) {
|
||||||
|
m_sceneManager.switchTo(std::move(e.nextScene), std::move(e.onSceneLoaded));
|
||||||
|
}
|
||||||
|
}, event);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application() = default;
|
||||||
|
|
||||||
|
void Application::run() {
|
||||||
|
auto lastTime = static_cast<float>(glfwGetTime());
|
||||||
|
|
||||||
|
while (!m_window->shouldClose()) {
|
||||||
|
const auto currentTime = static_cast<float>(glfwGetTime());
|
||||||
|
const float deltaTime = currentTime - lastTime;
|
||||||
|
lastTime = currentTime;
|
||||||
|
|
||||||
|
m_window->pollEvents();
|
||||||
|
|
||||||
|
|
||||||
|
m_imguiContext.beginFrame();
|
||||||
|
|
||||||
|
onUpdate(deltaTime);
|
||||||
|
|
||||||
|
GLStateCache::clearFrameBuffer(m_config.clearColor);
|
||||||
|
|
||||||
|
onRender();
|
||||||
|
|
||||||
|
m_imguiContext.endFrame();
|
||||||
|
m_window->swapBuffers();
|
||||||
|
|
||||||
|
m_keyboard.update();
|
||||||
|
m_mouse.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
engine/src/core/Application.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_APPLICATION_H
|
||||||
|
#define COLORRACE_APPLICATION_H
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "EngineConfig.h"
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
#include "audio/AudioDevice.h"
|
||||||
|
#include "events/ApplicationEvents.h"
|
||||||
|
#include "inputsOutputs/context/InputContextStack.h"
|
||||||
|
#include "inputsOutputs/inputs/Keyboard.h"
|
||||||
|
#include "inputsOutputs/inputs/Mouse.h"
|
||||||
|
#include "layer/SceneManager.h"
|
||||||
|
#include "ui/ImGuiContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Application {
|
||||||
|
public:
|
||||||
|
Application(const EngineConfig& config);
|
||||||
|
virtual ~Application();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
void requestClose();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onUpdate(float deltaTime) {}
|
||||||
|
virtual void onRender() {}
|
||||||
|
InputContextStack& getInputContextStack() { return m_inputContextStack; }
|
||||||
|
SceneManager& getSceneManager() { return m_sceneManager; }
|
||||||
|
Keyboard& getKeyboard() { return m_keyboard; }
|
||||||
|
Mouse& getMouse() { return m_mouse; }
|
||||||
|
|
||||||
|
std::shared_ptr<EventBus<ApplicationEvents>> m_applicationEventBus;
|
||||||
|
private:
|
||||||
|
EngineConfig m_config;
|
||||||
|
std::unique_ptr<Window> m_window;
|
||||||
|
InputContextStack m_inputContextStack;
|
||||||
|
Keyboard m_keyboard{*m_window}; // braucht Window& im Konstruktor
|
||||||
|
Mouse m_mouse{*m_window};
|
||||||
|
SceneManager m_sceneManager{m_inputContextStack};
|
||||||
|
ImGuiContext m_imguiContext{*m_window}; // neu
|
||||||
|
engine::audio::AudioDevice m_audioDevice;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_APPLICATION_H
|
||||||
28
engine/src/core/EngineConfig.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ENGINECONFIG_H
|
||||||
|
#define COLORRACE_ENGINECONFIG_H
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "glm/vec4.hpp"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct EngineConfig {
|
||||||
|
int windowWidth = 1280;
|
||||||
|
int windowHeight = 720;
|
||||||
|
std::string windowTitle = "Engine";
|
||||||
|
|
||||||
|
bool fullscreen = false;
|
||||||
|
bool vsync = true;
|
||||||
|
bool msaa = true;
|
||||||
|
int msaaSamples = 4;
|
||||||
|
|
||||||
|
glm::vec4 clearColor = {0.1f, 0.1f, 0.15f, 1.0f};
|
||||||
|
|
||||||
|
bool debugContext = true; // GL_DEBUG_OUTPUT an/aus
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_ENGINECONFIG_H
|
||||||
91
engine/src/core/Window.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "EngineConfig.h"
|
||||||
|
#include "glad/glad.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "utils/openglWrapper/GLStateCache.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
static void GLAPIENTRY DebugCallback(GLenum source, GLenum type, GLuint id,
|
||||||
|
GLenum severity, GLsizei length,
|
||||||
|
const GLchar* message, const void* userParam) {
|
||||||
|
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) return; // Spam raus
|
||||||
|
std::cerr << "[GL DEBUG] " << message << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::Window(const EngineConfig& config) {
|
||||||
|
if (!glfwInit()) throw std::runtime_error("GLFW init failed");
|
||||||
|
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, config.debugContext ? GLFW_TRUE : GLFW_FALSE);
|
||||||
|
|
||||||
|
if (config.msaa) {
|
||||||
|
glfwWindowHint(GLFW_SAMPLES, config.msaaSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLFWmonitor* monitor = config.fullscreen ? glfwGetPrimaryMonitor() : nullptr;
|
||||||
|
m_handle = glfwCreateWindow(config.windowWidth, config.windowHeight, config.windowTitle.c_str(), monitor, nullptr);
|
||||||
|
if (!m_handle) {
|
||||||
|
glfwTerminate();
|
||||||
|
throw std::runtime_error("Window creation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwMakeContextCurrent(m_handle);
|
||||||
|
glfwSwapInterval(config.vsync ? 1 : 0); // VSync
|
||||||
|
|
||||||
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||||
|
throw std::runtime_error("GLAD init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLStateCache::init();
|
||||||
|
|
||||||
|
if (config.debugContext) {
|
||||||
|
std::cout << "Debug Context should be enabled" << std::endl;
|
||||||
|
glEnable(GL_DEBUG_OUTPUT);
|
||||||
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
|
glDebugMessageCallback(DebugCallback, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.msaa) {
|
||||||
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glViewport(0, 0, config.windowWidth, config.windowHeight);
|
||||||
|
glfwSetWindowUserPointer(m_handle, &m_callbackTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window() {
|
||||||
|
glfwDestroyWindow(m_handle);
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::shouldClose() const { return glfwWindowShouldClose(m_handle); }
|
||||||
|
void Window::swapBuffers() { glfwSwapBuffers(m_handle); }
|
||||||
|
void Window::pollEvents() { glfwPollEvents(); }
|
||||||
|
|
||||||
|
int Window::getWidth() const {
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(m_handle, &width, &height);
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Window::getHeight() const {
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(m_handle, &width, &height);
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::requestWindowClose() {
|
||||||
|
glfwSetWindowShouldClose(m_handle, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
engine/src/core/Window.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_WINDOW_H
|
||||||
|
#define COLORRACE_WINDOW_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "EngineConfig.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct GLFWwindow;
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Keyboard;
|
||||||
|
class Mouse;
|
||||||
|
|
||||||
|
class Window {
|
||||||
|
public:
|
||||||
|
struct CallbackTarget {
|
||||||
|
Mouse* mouse = nullptr;
|
||||||
|
Keyboard* keyboard = nullptr;
|
||||||
|
};
|
||||||
|
Window(const EngineConfig& config);
|
||||||
|
~Window();
|
||||||
|
|
||||||
|
bool shouldClose() const;
|
||||||
|
void swapBuffers();
|
||||||
|
void pollEvents();
|
||||||
|
|
||||||
|
[[nodiscard]] GLFWwindow* getHandle() const { return m_handle; }
|
||||||
|
[[nodiscard]] int getWidth() const;
|
||||||
|
[[nodiscard]] int getHeight() const;
|
||||||
|
|
||||||
|
void setMouse(Mouse* mouse) { m_callbackTarget.mouse = mouse; }
|
||||||
|
void setKeyboard(Keyboard* keyboard) { m_callbackTarget.keyboard = keyboard; }
|
||||||
|
|
||||||
|
void requestWindowClose();
|
||||||
|
private:
|
||||||
|
GLFWwindow* m_handle;
|
||||||
|
CallbackTarget m_callbackTarget;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_WINDOW_H
|
||||||
53
engine/src/core/animation/AnimationSystem.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AnimationSystem.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "components/TransformAnimationComponent.h"
|
||||||
|
#include "ecs/standardComponents/TransformComponent.h"
|
||||||
|
|
||||||
|
namespace engine::animation {
|
||||||
|
void animation::AnimationSystem::update(float deltaTime) {
|
||||||
|
std::vector<engine::Entity> toRemove;
|
||||||
|
for (auto& [entity, animation] : m_registry.getPool<TransformAnimationComponent>()) {
|
||||||
|
animation.time += deltaTime;
|
||||||
|
|
||||||
|
while (animation.nextMarkerIndex < animation.markers.size() && animation.markers[animation.nextMarkerIndex].time <= animation.time) {
|
||||||
|
animation.markers[animation.nextMarkerIndex].callback();
|
||||||
|
animation.nextMarkerIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& transform = m_registry.getComponent<TransformComponent>(entity);
|
||||||
|
|
||||||
|
if (!animation.position.keys.empty()) {
|
||||||
|
transform.m_position = evaluate(animation.position, animation.time);
|
||||||
|
}
|
||||||
|
if (!animation.rotation.keys.empty()) {
|
||||||
|
transform.m_rotation = evaluate(animation.rotation, animation.time);
|
||||||
|
}
|
||||||
|
if (!animation.scale.keys.empty()) {
|
||||||
|
transform.m_scale = evaluate(animation.scale, animation.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animation.time >= animation.duration) {
|
||||||
|
if (animation.loop) {
|
||||||
|
animation.time = 0.f;
|
||||||
|
animation.nextMarkerIndex = 0;
|
||||||
|
} else {
|
||||||
|
if (animation.onFinished) {
|
||||||
|
animation.onFinished();
|
||||||
|
}
|
||||||
|
animation.finished = true;
|
||||||
|
toRemove.push_back(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto entity : toRemove) {
|
||||||
|
m_registry.removeComponent<TransformAnimationComponent>(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // engine
|
||||||
60
engine/src/core/animation/AnimationSystem.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ANIMATIONSYSTEM_H
|
||||||
|
#define COLORRACE_ANIMATIONSYSTEM_H
|
||||||
|
#include "components/TransformAnimationComponent.h"
|
||||||
|
#include "ecs/EntityRegistry.h"
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
namespace engine::animation {
|
||||||
|
class AnimationSystem {
|
||||||
|
public:
|
||||||
|
explicit AnimationSystem(EntityRegistry& registry) : m_registry(registry) {}
|
||||||
|
void update(float deltaTime);
|
||||||
|
private:
|
||||||
|
EntityRegistry& m_registry;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T evaluate(const AnimationTrack<T>& track, float time) {
|
||||||
|
Keyframe<T> a;
|
||||||
|
Keyframe<T> b;
|
||||||
|
findSurroundingKeys(track, time, a, b);
|
||||||
|
|
||||||
|
if (a.time == b.time) return a.value;
|
||||||
|
|
||||||
|
float localT = (time - a.time) / (b.time - a.time);
|
||||||
|
float easedT = a.easingFunction(localT);
|
||||||
|
return glm::mix(a.value, b.value, easedT);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void findSurroundingKeys(const AnimationTrack<T>& track, float time, Keyframe<T>& a, Keyframe<T>& b) {
|
||||||
|
if (track.keys.size() == 1) {
|
||||||
|
a = b = track.keys.front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time <= track.keys.front().time) {
|
||||||
|
a = b = track.keys.front();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time >= track.keys.back().time) {
|
||||||
|
a = b = track.keys.back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1; i < track.keys.size(); ++i) {
|
||||||
|
if (track.keys[i - 1].time <= time && track.keys[i].time >= time) {
|
||||||
|
a = track.keys[i - 1];
|
||||||
|
b = track.keys[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
} // engine
|
||||||
|
|
||||||
|
#endif //COLORRACE_ANIMATIONSYSTEM_H
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_BLOCKINGANIMATIONCOMPONENT_H
|
||||||
|
#define COLORRACE_BLOCKINGANIMATIONCOMPONENT_H
|
||||||
|
namespace engine::animation {
|
||||||
|
struct BlockingAnimationComponent {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_BLOCKINGANIMATIONCOMPONENT_H
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_TRANSFORMANIMATIONCOMPONENT_H
|
||||||
|
#define COLORRACE_TRANSFORMANIMATIONCOMPONENT_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
namespace engine::animation {
|
||||||
|
using EasingFunction = std::function<float(float)>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Keyframe {
|
||||||
|
float time;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
EasingFunction easingFunction = [](float t) {
|
||||||
|
return t;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimationMarker {
|
||||||
|
float time;
|
||||||
|
std::function<void()> callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct AnimationTrack {
|
||||||
|
std::vector<Keyframe<T>> keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransformAnimationComponent {
|
||||||
|
float time = 0.0f;
|
||||||
|
float duration = 0.0f;
|
||||||
|
|
||||||
|
AnimationTrack<glm::vec3> position;
|
||||||
|
AnimationTrack<glm::vec3> rotation;
|
||||||
|
AnimationTrack<glm::vec3> scale;
|
||||||
|
|
||||||
|
std::vector<AnimationMarker> markers;
|
||||||
|
size_t nextMarkerIndex = 0;
|
||||||
|
|
||||||
|
std::function<void()> onFinished;
|
||||||
|
bool loop = false;
|
||||||
|
bool finished = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_TRANSFORMANIMATIONCOMPONENT_H
|
||||||
18
engine/src/core/animation/events/AnimationMarkerEvent.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ANIMATIONMARKEREVENT_H
|
||||||
|
#define COLORRACE_ANIMATIONMARKEREVENT_H
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ecs/Entity.h"
|
||||||
|
|
||||||
|
namespace engine::animation {
|
||||||
|
struct AnimationMarkerEvent {
|
||||||
|
engine::Entity entity;
|
||||||
|
std::string tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_ANIMATIONMARKEREVENT_H
|
||||||
24
engine/src/core/audio/AudioDevice.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AudioDevice.h"
|
||||||
|
|
||||||
|
engine::audio::AudioDevice::AudioDevice() {
|
||||||
|
m_device = alcOpenDevice(nullptr);
|
||||||
|
if (!m_device) {
|
||||||
|
throw std::runtime_error("Kein Audio-Device gefunden");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context = alcCreateContext(m_device, nullptr);
|
||||||
|
if (!m_context) {
|
||||||
|
throw std::runtime_error("Kein Audio-Context gefunden");
|
||||||
|
}
|
||||||
|
alcMakeContextCurrent(m_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::audio::AudioDevice::~AudioDevice() {
|
||||||
|
alcMakeContextCurrent(nullptr);
|
||||||
|
if (m_context) alcDestroyContext(m_context);
|
||||||
|
if (m_device) alcCloseDevice(m_device);
|
||||||
|
}
|
||||||
37
engine/src/core/audio/AudioDevice.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_AUDIODEVICE_H
|
||||||
|
#define COLORRACE_AUDIODEVICE_H
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "al.h"
|
||||||
|
#include "alc.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
class AudioDevice {
|
||||||
|
public:
|
||||||
|
AudioDevice();
|
||||||
|
|
||||||
|
~AudioDevice();
|
||||||
|
// Kein Kopieren/Verschieben nötig für den Anfang
|
||||||
|
AudioDevice(const AudioDevice&) = delete;
|
||||||
|
AudioDevice& operator=(const AudioDevice&) = delete;
|
||||||
|
private:
|
||||||
|
ALCdevice* m_device = nullptr;
|
||||||
|
ALCcontext* m_context = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void checkAlError(const char* location) {
|
||||||
|
ALenum err = alGetError();
|
||||||
|
if (err != AL_NO_ERROR) {
|
||||||
|
std::cerr << "OpenAL Error: " << alGetString(err) << " at " << location << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_AUDIODEVICE_H
|
||||||
31
engine/src/core/audio/SoundBuffer.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SoundBuffer.h"
|
||||||
|
|
||||||
|
#include <dr_wav.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "AudioDevice.h"
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
SoundBuffer::~SoundBuffer() {
|
||||||
|
if (m_bufferID) alDeleteBuffers(1, &m_bufferID);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundBuffer::SoundBuffer(SoundBuffer &&other) noexcept : m_bufferID(other.m_bufferID) {
|
||||||
|
other.m_bufferID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundBuffer & SoundBuffer::operator=(SoundBuffer &&other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
release();
|
||||||
|
|
||||||
|
m_bufferID = other.m_bufferID;
|
||||||
|
other.m_bufferID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
} // engine
|
||||||
39
engine/src/core/audio/SoundBuffer.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_SOUNDBUFFER_H
|
||||||
|
#define COLORRACE_SOUNDBUFFER_H
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "al.h"
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
class SoundBuffer {
|
||||||
|
public:
|
||||||
|
explicit SoundBuffer(ALuint bufferID) : m_bufferID(bufferID) {}
|
||||||
|
~SoundBuffer();
|
||||||
|
|
||||||
|
SoundBuffer(const SoundBuffer&) = delete;
|
||||||
|
|
||||||
|
SoundBuffer& operator=(const SoundBuffer&) = delete;
|
||||||
|
|
||||||
|
SoundBuffer(SoundBuffer&& other) noexcept;
|
||||||
|
SoundBuffer& operator=(SoundBuffer&& other) noexcept;
|
||||||
|
|
||||||
|
ALuint id() const {
|
||||||
|
return m_bufferID;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ALuint m_bufferID = 0;
|
||||||
|
|
||||||
|
void release() {
|
||||||
|
if (m_bufferID != 0) {
|
||||||
|
alDeleteBuffers(1, &m_bufferID);
|
||||||
|
m_bufferID = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // engine
|
||||||
|
|
||||||
|
#endif //COLORRACE_SOUNDBUFFER_H
|
||||||
8
engine/src/core/audio/SoundSource.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SoundSource.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
} // engine
|
||||||
90
engine/src/core/audio/SoundSource.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_SOUNDSOURCE_H
|
||||||
|
#define COLORRACE_SOUNDSOURCE_H
|
||||||
|
#include "al.h"
|
||||||
|
#include "AudioDevice.h"
|
||||||
|
#include "SoundBuffer.h"
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
|
||||||
|
class SoundSource {
|
||||||
|
public:
|
||||||
|
SoundSource() {
|
||||||
|
alGenSources(1, &m_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SoundSource() {
|
||||||
|
if (m_source) alDeleteSources(1, &m_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundSource(const SoundSource&) = delete;
|
||||||
|
SoundSource& operator=(const SoundSource&) = delete;
|
||||||
|
|
||||||
|
SoundSource(SoundSource&& other) noexcept
|
||||||
|
: m_source(other.m_source)
|
||||||
|
{
|
||||||
|
other.m_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundSource& operator=(SoundSource&& other) noexcept
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
release();
|
||||||
|
|
||||||
|
m_source = other.m_source;
|
||||||
|
other.m_source = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuffer(const SoundBuffer& buffer) {
|
||||||
|
alSourcei(m_source, AL_BUFFER, static_cast<ALint>(buffer.id()));
|
||||||
|
checkAlError("alSourcei(AL_BUFFER)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition(float x, float y, float z) {
|
||||||
|
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGain(float gain) {
|
||||||
|
alSourcef(m_source, AL_GAIN, gain);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLooping(bool loop) {
|
||||||
|
alSourcei(m_source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void play() { alSourcePlay(m_source); }
|
||||||
|
void stop() { alSourceStop(m_source); }
|
||||||
|
|
||||||
|
bool isPlaying() const {
|
||||||
|
ALint state;
|
||||||
|
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||||
|
return state == AL_PLAYING;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ALuint m_source = 0;
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
if (m_source != 0) {
|
||||||
|
alDeleteSources(1, &m_source);
|
||||||
|
m_source = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void updateListener(float px, float py, float pz,
|
||||||
|
float fx, float fy, float fz,
|
||||||
|
float ux, float uy, float uz) {
|
||||||
|
alListener3f(AL_POSITION, px, py, pz);
|
||||||
|
ALfloat orientation[] = { fx, fy, fz, ux, uy, uz };
|
||||||
|
alListenerfv(AL_ORIENTATION, orientation);
|
||||||
|
}
|
||||||
|
} // engine
|
||||||
|
|
||||||
|
#endif //COLORRACE_SOUNDSOURCE_H
|
||||||
34
engine/src/core/audio/ecs/AudioSystem.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AudioSystem.h"
|
||||||
|
|
||||||
|
#include "BlockingSoundComponent.h"
|
||||||
|
#include "PlaySoundComponent.h"
|
||||||
|
#include "core/audio/SoundSource.h"
|
||||||
|
|
||||||
|
void engine::audio::AudioSystem::update(float deltaTime) const {
|
||||||
|
std::vector<Entity> toRemove;
|
||||||
|
|
||||||
|
for (auto& [entity, playSound] : m_registry.getPool<PlaySoundComponent>()) {
|
||||||
|
auto& source = m_registry.getComponent<SoundSource>(entity);
|
||||||
|
if (!playSound.started) {
|
||||||
|
source.setGain(playSound.gain);
|
||||||
|
source.play();
|
||||||
|
playSound.started = true;
|
||||||
|
} else if (!source.isPlaying()) {
|
||||||
|
if (playSound.onFinished) {
|
||||||
|
playSound.onFinished();
|
||||||
|
}
|
||||||
|
toRemove.push_back(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto entity : toRemove) {
|
||||||
|
m_registry.removeComponent<PlaySoundComponent>(entity);
|
||||||
|
if (m_registry.hasComponent<BlockingSoundComponent>(entity)) {
|
||||||
|
m_registry.removeComponent<BlockingSoundComponent>(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
engine/src/core/audio/ecs/AudioSystem.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_AUDIOSYSTEM_H
|
||||||
|
#define COLORRACE_AUDIOSYSTEM_H
|
||||||
|
#include "ecs/EntityRegistry.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
class AudioSystem {
|
||||||
|
public:
|
||||||
|
explicit AudioSystem(EntityRegistry& registry) : m_registry(registry) {}
|
||||||
|
void update(float deltaTime) const;
|
||||||
|
private:
|
||||||
|
EntityRegistry& m_registry;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_AUDIOSYSTEM_H
|
||||||
10
engine/src/core/audio/ecs/BlockingSoundComponent.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||||
|
#define COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||||
|
namespace engine::audio {
|
||||||
|
struct BlockingSoundComponent {};
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_BLOCKINGSOUNDCOMPONENT_H
|
||||||
21
engine/src/core/audio/ecs/PlaySoundComponent.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||||
|
#define COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "../SoundBuffer.h"
|
||||||
|
|
||||||
|
namespace engine::audio {
|
||||||
|
struct PlaySoundComponent {
|
||||||
|
float gain = 1.f;
|
||||||
|
bool started = false;
|
||||||
|
bool blocking = false;
|
||||||
|
std::function<void()> onFinished;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_PLAYSOUNDCOMPONENT_H
|
||||||
14
engine/src/core/events/ApplicationEvents.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 07.08.26.
|
||||||
|
//
|
||||||
|
#include "ApplicationEvents.h"
|
||||||
|
#include "layer/Scene.h" // hier ist Scene vollständig bekannt
|
||||||
|
|
||||||
|
SceneSwitchRequested::SceneSwitchRequested() = default;
|
||||||
|
|
||||||
|
SceneSwitchRequested::SceneSwitchRequested(std::unique_ptr<engine::Scene> scene, std::function<void()> callback) : nextScene(std::move(scene)), onSceneLoaded(std::move(callback)){
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneSwitchRequested::~SceneSwitchRequested() = default;
|
||||||
|
SceneSwitchRequested::SceneSwitchRequested(SceneSwitchRequested&&) noexcept = default;
|
||||||
|
SceneSwitchRequested& SceneSwitchRequested::operator=(SceneSwitchRequested&&) noexcept = default;
|
||||||
31
engine/src/core/events/ApplicationEvents.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 06.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_APPLICATIONEVENTS_H
|
||||||
|
#define COLORRACE_APPLICATIONEVENTS_H
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct QuitRequested {};
|
||||||
|
|
||||||
|
struct SceneSwitchRequested {
|
||||||
|
std::unique_ptr<engine::Scene> nextScene;
|
||||||
|
std::function<void()> onSceneLoaded;
|
||||||
|
|
||||||
|
SceneSwitchRequested();
|
||||||
|
SceneSwitchRequested(std::unique_ptr<engine::Scene> scene, std::function<void()> callback);
|
||||||
|
~SceneSwitchRequested();
|
||||||
|
SceneSwitchRequested(SceneSwitchRequested&&) noexcept;
|
||||||
|
SceneSwitchRequested& operator=(SceneSwitchRequested&&) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using ApplicationEvents = std::variant<QuitRequested, SceneSwitchRequested>;
|
||||||
|
#endif //COLORRACE_APPLICATIONEVENTS_H
|
||||||
8
engine/src/core/events/EventBus.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EventBus.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
} // engine
|
||||||
42
engine/src/core/events/EventBus.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 05.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_EVENTBUS_H
|
||||||
|
#define COLORRACE_EVENTBUS_H
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class IEventBus {
|
||||||
|
public:
|
||||||
|
virtual ~IEventBus() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Event>
|
||||||
|
class EventBus {
|
||||||
|
public:
|
||||||
|
using Handler = std::function<void(Event&)>;
|
||||||
|
|
||||||
|
void subscribe(Handler handler) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
m_handlers.push_back(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void publish(Event& event) const {
|
||||||
|
std::vector<Handler> handlersCopy;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(m_mutex);
|
||||||
|
handlersCopy = m_handlers;
|
||||||
|
}
|
||||||
|
for (const auto& handler : handlersCopy) {
|
||||||
|
handler(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
|
std::vector<Handler> m_handlers;
|
||||||
|
};
|
||||||
|
} // engine
|
||||||
|
|
||||||
|
#endif //COLORRACE_EVENTBUS_H
|
||||||
5
engine/src/core/events/EventChannels.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 06.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EventChannels.h"
|
||||||
43
engine/src/core/events/EventChannels.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 06.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_EVENTCHANNELS_H
|
||||||
|
#define COLORRACE_EVENTCHANNELS_H
|
||||||
|
#include <memory>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
#include "EventBus.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class EventChannels {
|
||||||
|
public:
|
||||||
|
template<typename Event>
|
||||||
|
void subscribe(typename EventBus<Event>::Handler handler) {
|
||||||
|
getBus<Event>().subscribe(std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Event>
|
||||||
|
void publish(Event& event) {
|
||||||
|
getBus<Event>().publish(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Event>
|
||||||
|
EventBus<Event>& getBus() {
|
||||||
|
auto key = std::type_index(typeid(Event));
|
||||||
|
auto it = m_buses.find(key);
|
||||||
|
if (it == m_buses.end()) {
|
||||||
|
auto bus = std::make_unique<EventBus<Event>>();
|
||||||
|
auto* ptr = bus.get();
|
||||||
|
m_buses.emplace(key, std::move(bus));
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
return static_cast<EventBus<Event>&>(*it->second);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::type_index, std::unique_ptr<IEventBus>> m_buses;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_EVENTCHANNELS_H
|
||||||
5
engine/src/core/inputsOutputs/context/InputContext.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InputContext.h"
|
||||||
19
engine/src/core/inputsOutputs/context/InputContext.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_INPUTCONTEXT_H
|
||||||
|
#define COLORRACE_INPUTCONTEXT_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class InputContext {
|
||||||
|
public:
|
||||||
|
virtual ~InputContext() = default;
|
||||||
|
virtual void onActivate() {};
|
||||||
|
virtual void onDeactivate() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_INPUTCONTEXT_H
|
||||||
24
engine/src/core/inputsOutputs/context/InputContextStack.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InputContextStack.h"
|
||||||
|
|
||||||
|
|
||||||
|
void engine::InputContextStack::push(std::shared_ptr<InputContext> context) {
|
||||||
|
if (!m_stack.empty()) m_stack.back()->onDeactivate();
|
||||||
|
context->onActivate();
|
||||||
|
m_stack.push_back(std::move(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::InputContextStack::pop() {
|
||||||
|
if (m_stack.empty()) return;
|
||||||
|
m_stack.back()->onDeactivate();
|
||||||
|
m_stack.pop_back();
|
||||||
|
if (!m_stack.empty()) m_stack.back()->onActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool engine::InputContextStack::isActive(const InputContext &context) const {
|
||||||
|
return !m_stack.empty() && m_stack.back().get() == &context;
|
||||||
|
}
|
||||||
25
engine/src/core/inputsOutputs/context/InputContextStack.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_INPUTCONTEXTSTACK_H
|
||||||
|
#define COLORRACE_INPUTCONTEXTSTACK_H
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "InputContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class InputContextStack {
|
||||||
|
public:
|
||||||
|
void push(std::shared_ptr<InputContext> context);
|
||||||
|
void pop();
|
||||||
|
[[nodiscard]] bool isActive(const InputContext& context) const;
|
||||||
|
private:
|
||||||
|
std::vector<std::shared_ptr<InputContext>> m_stack;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_INPUTCONTEXTSTACK_H
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "CameraController.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "glm/vec3.hpp"
|
||||||
|
#include "renderer/entities/Camera.h"
|
||||||
|
|
||||||
|
void engine::CameraController::update(const Keyboard &keyboard, Camera &camera, float deltaTime) {
|
||||||
|
if (!m_stack.isActive(*m_gameContext.get())) return;
|
||||||
|
|
||||||
|
|
||||||
|
if (keyboard.isKeyDown(GLFW_KEY_W)) camera.moveRelative(glm::vec3(0.0f, 0.0f, 1.0f), 10.0f, deltaTime);
|
||||||
|
if (keyboard.isKeyDown(GLFW_KEY_S)) camera.moveRelative(glm::vec3(0.0f, 0.0f, -1.0f), 10.0f, deltaTime);
|
||||||
|
if (keyboard.isKeyDown(GLFW_KEY_A)) camera.moveRelative(glm::vec3(-1.0f, 0.0f, 0.0f), 10.0f, deltaTime);
|
||||||
|
if (keyboard.isKeyDown(GLFW_KEY_D)) camera.moveRelative(glm::vec3(1.0f, 0.0f, 0.0f), 10.0f, deltaTime);
|
||||||
|
if (keyboard.isKeyDown(GLFW_KEY_SPACE)) camera.moveRelative(glm::vec3(0.0f, 1.0f, 0.0f), 10.0f, deltaTime);
|
||||||
|
}
|
||||||
25
engine/src/core/inputsOutputs/controller/CameraController.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_CAMERACONTROLLER_H
|
||||||
|
#define COLORRACE_CAMERACONTROLLER_H
|
||||||
|
#include "core/inputsOutputs/context/InputContextStack.h"
|
||||||
|
#include "core/inputsOutputs/inputs/Keyboard.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Camera;
|
||||||
|
|
||||||
|
class CameraController {
|
||||||
|
public:
|
||||||
|
CameraController(InputContextStack& stack, std::shared_ptr<InputContext> gameContext) : m_stack(stack), m_gameContext(std::move(gameContext)) {}
|
||||||
|
void update(const Keyboard& keyboard, Camera& camera, float deltaTime);
|
||||||
|
private:
|
||||||
|
InputContextStack& m_stack;
|
||||||
|
std::shared_ptr<InputContext> m_gameContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_CAMERACONTROLLER_H
|
||||||
82
engine/src/core/inputsOutputs/inputs/Keyboard.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Keyboard.h"
|
||||||
|
|
||||||
|
#include "imgui_impl_glfw.h"
|
||||||
|
#include "core/Window.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
engine::Keyboard::Keyboard(engine::Window &window) {
|
||||||
|
window.setKeyboard(this);
|
||||||
|
addKeyListener(window);
|
||||||
|
addTextListener(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::update() {
|
||||||
|
keysPressedThisFrame.clear();
|
||||||
|
keysRepeatedThisFrame.clear();
|
||||||
|
charsThisFrame.clear();
|
||||||
|
keysReleasedThisFrame.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::Keyboard::isKeyDown(const int key) const {
|
||||||
|
return keysDown.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<int> & engine::Keyboard::getCharsThisFrame() {
|
||||||
|
return charsThisFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto engine::Keyboard::keyPressEvent(const int key) const -> bool {
|
||||||
|
return keysPressedThisFrame.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto engine::Keyboard::keyPressEvent(const int key, bool checkRepeats) const -> bool {
|
||||||
|
return keysPressedThisFrame.contains(key) || (checkRepeats && keysRepeatedThisFrame.contains(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::Keyboard::keyReleaseEvent(const int key) const {
|
||||||
|
return keysReleasedThisFrame.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::addTextListener(Window &window) {
|
||||||
|
glfwSetCharCallback(window.getHandle(), [](GLFWwindow* handle, unsigned int key) {
|
||||||
|
ImGui_ImplGlfw_CharCallback(handle, key);
|
||||||
|
auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
|
||||||
|
if (!target || !target->keyboard) return;
|
||||||
|
|
||||||
|
target->keyboard->reportChar(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::addKeyListener(Window &window) {
|
||||||
|
glfwSetKeyCallback(window.getHandle(), [](GLFWwindow* handle, int key, int scancode, int action, int mods) {
|
||||||
|
ImGui_ImplGlfw_KeyCallback(handle, key, scancode, action, mods);
|
||||||
|
auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
|
||||||
|
if (!target || !target->keyboard) return;
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS) target->keyboard->reportKeyPress(key);
|
||||||
|
else if (action == GLFW_RELEASE) target->keyboard->reportKeyRelease(key);
|
||||||
|
else if (action == GLFW_REPEAT) target->keyboard->reportKeyRepeat(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::reportKeyPress(int key) {
|
||||||
|
keysDown.insert(key);
|
||||||
|
keysPressedThisFrame.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::reportKeyRelease(int key) {
|
||||||
|
keysDown.erase(key);
|
||||||
|
keysReleasedThisFrame.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::reportKeyRepeat(int key) {
|
||||||
|
keysRepeatedThisFrame.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Keyboard::reportChar(int key) {
|
||||||
|
charsThisFrame.push_back(key);
|
||||||
|
}
|
||||||
46
engine/src/core/inputsOutputs/inputs/Keyboard.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_KEYBOARD_H
|
||||||
|
#define COLORRACE_KEYBOARD_H
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
|
||||||
|
class Keyboard {
|
||||||
|
public:
|
||||||
|
explicit Keyboard(engine::Window& window);
|
||||||
|
|
||||||
|
void update();
|
||||||
|
bool isKeyDown(int key) const;
|
||||||
|
|
||||||
|
const std::vector<int> &getCharsThisFrame();
|
||||||
|
|
||||||
|
bool keyPressEvent(int key) const;
|
||||||
|
bool keyPressEvent(int key, bool checkRepeats) const;
|
||||||
|
bool keyReleaseEvent(int key) const;
|
||||||
|
private:
|
||||||
|
std::unordered_set<int> keysPressedThisFrame;
|
||||||
|
std::unordered_set<int> keysRepeatedThisFrame;
|
||||||
|
std::unordered_set<int> keysReleasedThisFrame;
|
||||||
|
std::unordered_set<int> keysDown;
|
||||||
|
std::vector<int> charsThisFrame;
|
||||||
|
|
||||||
|
void addTextListener(Window& window);
|
||||||
|
|
||||||
|
void addKeyListener(Window& window);
|
||||||
|
void reportKeyPress(int key);
|
||||||
|
void reportKeyRelease(int key);
|
||||||
|
void reportKeyRepeat(int key);
|
||||||
|
void reportChar(int key);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_KEYBOARD_H
|
||||||
124
engine/src/core/inputsOutputs/inputs/Mouse.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Mouse.h"
|
||||||
|
|
||||||
|
#include "imgui_impl_glfw.h"
|
||||||
|
#include "core/Window.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
engine::Mouse::Mouse(Window &window) {
|
||||||
|
window.setMouse(this);
|
||||||
|
addClickListener(window);
|
||||||
|
addMoveListener(window);
|
||||||
|
addScrollListener(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::Mouse::isButtonDown(const MouseButton button) const {
|
||||||
|
return buttonsDown.contains(MouseButtonToInt(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::Mouse::isClickEvent(const MouseButton button) const {
|
||||||
|
return buttonsClickedThisFrame.contains(MouseButtonToInt(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::Mouse::isReleaseEvent(const MouseButton button) const {
|
||||||
|
return buttonsReleasedThisFrame.contains(MouseButtonToInt(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::Mouse::getX(const bool ndc) const {
|
||||||
|
return ndc ? 2 * x - 1 : x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::Mouse::getY(const bool ndc) const {
|
||||||
|
return ndc ? 1 - 2 * y : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::Mouse::getDX() const {
|
||||||
|
return dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::Mouse::getDY() const {
|
||||||
|
return dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::Mouse::getScroll() const {
|
||||||
|
return scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::update() {
|
||||||
|
updateDetlas();
|
||||||
|
scroll = 0;
|
||||||
|
|
||||||
|
buttonsClickedThisFrame.clear();
|
||||||
|
buttonsReleasedThisFrame.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 engine::Mouse::getXY(bool ndc) const {
|
||||||
|
return {getX(ndc), getY(ndc)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::reportButtonClick(int button) {
|
||||||
|
spdlog::debug("Button {} clicked", button);
|
||||||
|
buttonsDown.insert(button);
|
||||||
|
buttonsClickedThisFrame.insert(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::reportButtonRelease(int button) {
|
||||||
|
buttonsDown.erase(button);
|
||||||
|
buttonsReleasedThisFrame.insert(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::updateDetlas() {
|
||||||
|
dx = x - lastX;
|
||||||
|
dy = y - lastY;
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::addMoveListener(Window &window) {
|
||||||
|
glfwSetCursorPosCallback(window.getHandle(), [](GLFWwindow* handle, double xPos, double yPos) {
|
||||||
|
ImGui_ImplGlfw_CursorPosCallback(handle, xPos, yPos);
|
||||||
|
|
||||||
|
auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
|
||||||
|
if (!target || !target->mouse) return;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(handle, &width, &height);
|
||||||
|
target->mouse->x = static_cast<float>(xPos / width);
|
||||||
|
target->mouse->y = static_cast<float>(yPos / height);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::addScrollListener(Window &window) {
|
||||||
|
glfwSetScrollCallback(window.getHandle(), [](GLFWwindow* handle, double xoff, double yoff) {
|
||||||
|
ImGui_ImplGlfw_ScrollCallback(handle, xoff, yoff);
|
||||||
|
|
||||||
|
auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
|
||||||
|
if (target && target->mouse) target->mouse->scroll = static_cast<float>(yoff);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Mouse::addClickListener(Window &window) {
|
||||||
|
glfwSetMouseButtonCallback(window.getHandle(), [](GLFWwindow* handle, int button, int action, int mods) {
|
||||||
|
ImGui_ImplGlfw_MouseButtonCallback(handle, button, action, mods);
|
||||||
|
|
||||||
|
auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
|
||||||
|
if (!target || !target->mouse) return;
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS) target->mouse->reportButtonClick(button);
|
||||||
|
else if (action == GLFW_RELEASE) target->mouse->reportButtonRelease(button);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int engine::Mouse::MouseButtonToInt(MouseButton button) {
|
||||||
|
int glfwButton = 0;
|
||||||
|
switch (button) {
|
||||||
|
case MouseButton::LEFT: glfwButton = GLFW_MOUSE_BUTTON_LEFT; break;
|
||||||
|
case MouseButton::RIGHT: glfwButton = GLFW_MOUSE_BUTTON_RIGHT; break;
|
||||||
|
case MouseButton::MIDDLE: glfwButton = GLFW_MOUSE_BUTTON_MIDDLE; break;
|
||||||
|
}
|
||||||
|
return glfwButton;
|
||||||
|
}
|
||||||
52
engine/src/core/inputsOutputs/inputs/Mouse.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_MOUSE_H
|
||||||
|
#define COLORRACE_MOUSE_H
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "MouseButton.h"
|
||||||
|
#include "glm/vec2.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Window;
|
||||||
|
|
||||||
|
class Mouse {
|
||||||
|
public:
|
||||||
|
explicit Mouse(Window& window);
|
||||||
|
bool isButtonDown(MouseButton button) const;
|
||||||
|
bool isClickEvent(MouseButton button) const;
|
||||||
|
bool isReleaseEvent(MouseButton button) const;
|
||||||
|
float getX(bool ndc) const;
|
||||||
|
float getY(bool ndc) const;
|
||||||
|
float getDX() const;
|
||||||
|
float getDY() const;
|
||||||
|
float getScroll() const;
|
||||||
|
void update();
|
||||||
|
glm::vec2 getXY(bool ndc) const;
|
||||||
|
private:
|
||||||
|
std::unordered_set<int> buttonsDown;
|
||||||
|
std::unordered_set<int> buttonsClickedThisFrame;
|
||||||
|
std::unordered_set<int> buttonsReleasedThisFrame;
|
||||||
|
|
||||||
|
float x = 0.0f, y = 0.0f;
|
||||||
|
float dx = 0.0f, dy = 0.0f;
|
||||||
|
float scroll = 0.0f;
|
||||||
|
float lastX = 0.0f, lastY = 0.0f;
|
||||||
|
|
||||||
|
void reportButtonClick(int button);
|
||||||
|
void reportButtonRelease(int button);
|
||||||
|
void updateDetlas();
|
||||||
|
|
||||||
|
static void addMoveListener(Window& window);
|
||||||
|
static void addScrollListener(Window& window);
|
||||||
|
static void addClickListener(Window& window);
|
||||||
|
|
||||||
|
static int MouseButtonToInt(MouseButton button);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_MOUSE_H
|
||||||
14
engine/src/core/inputsOutputs/inputs/MouseButton.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_MOUSEBUTTON_H
|
||||||
|
#define COLORRACE_MOUSEBUTTON_H
|
||||||
|
namespace engine {
|
||||||
|
enum class MouseButton {
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
MIDDLE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_MOUSEBUTTON_H
|
||||||
5
engine/src/ecs/ComponentPool.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ComponentPool.h"
|
||||||
50
engine/src/ecs/ComponentPool.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_COMPONENTPOOL_H
|
||||||
|
#define COLORRACE_COMPONENTPOOL_H
|
||||||
|
#include "Entity.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class IComponentPool {
|
||||||
|
public:
|
||||||
|
virtual ~IComponentPool() = default;
|
||||||
|
virtual void remove(Entity entity) = 0;
|
||||||
|
virtual size_t size() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class ComponentPool : public IComponentPool {
|
||||||
|
public:
|
||||||
|
void remove(Entity entity) override {
|
||||||
|
m_components.erase(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(Entity entity, T component) {
|
||||||
|
m_components[entity] = std::move(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool has(Entity entity) const {
|
||||||
|
return m_components.contains(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get(Entity entity) {
|
||||||
|
return m_components.at(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() override {
|
||||||
|
return m_components.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Für Iteration in Systemen
|
||||||
|
auto begin() { return m_components.begin(); }
|
||||||
|
auto end() { return m_components.end(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<Entity, T> m_components;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_COMPONENTPOOL_H
|
||||||
5
engine/src/ecs/Entity.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
39
engine/src/ecs/Entity.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ENTITY_H
|
||||||
|
#define COLORRACE_ENTITY_H
|
||||||
|
#include <cstdint>
|
||||||
|
#include <limits>
|
||||||
|
#include <functional> // <- das hier fehlt vermutlich
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Entity {
|
||||||
|
public:
|
||||||
|
constexpr Entity() noexcept = default;
|
||||||
|
constexpr explicit Entity(std::uint32_t id) noexcept : m_id(id) {}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr std::uint32_t value() const noexcept { return m_id; }
|
||||||
|
|
||||||
|
constexpr bool operator==(const Entity&) const = default;
|
||||||
|
|
||||||
|
static constexpr Entity null() noexcept {
|
||||||
|
return Entity{std::numeric_limits<std::uint32_t>::max()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::uint32_t m_id = std::numeric_limits<std::uint32_t>::max();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Damit Entity in unordered_map als Key funktioniert
|
||||||
|
template<>
|
||||||
|
struct std::hash<engine::Entity> {
|
||||||
|
std::size_t operator()(const engine::Entity& e) const noexcept {
|
||||||
|
return std::hash<std::uint32_t>{}(e.value());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_ENTITY_H
|
||||||
5
engine/src/ecs/EntityRegistry.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EntityRegistry.h"
|
||||||
70
engine/src/ecs/EntityRegistry.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ENTITYREGISTRY_H
|
||||||
|
#define COLORRACE_ENTITYREGISTRY_H
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "ComponentPool.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class EntityRegistry {
|
||||||
|
public:
|
||||||
|
Entity createEntity() {
|
||||||
|
return Entity{m_nextId++};
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyEntity(Entity entity) {
|
||||||
|
for (auto& [type, pool] : m_pools) {
|
||||||
|
pool->remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void addComponent(Entity entity, T component) {
|
||||||
|
getPool<T>().insert(entity, std::move(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void removeComponent(Entity entity) {
|
||||||
|
getPool<T>().remove(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] bool hasComponent(Entity entity) {
|
||||||
|
auto key = std::type_index(typeid(T));
|
||||||
|
auto it = m_pools.find(key);
|
||||||
|
if (it == m_pools.end()) return false;
|
||||||
|
return static_cast<ComponentPool<T>&>(*it->second).has(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T& getComponent(Entity entity) {
|
||||||
|
return getPool<T>().get(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ComponentPool<T>& getPool() {
|
||||||
|
auto key = std::type_index(typeid(T));
|
||||||
|
auto it = m_pools.find(key);
|
||||||
|
if (it == m_pools.end()) {
|
||||||
|
auto pool = std::make_unique<ComponentPool<T>>();
|
||||||
|
auto* ptr = pool.get();
|
||||||
|
m_pools.emplace(key, std::move(pool));
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
return static_cast<ComponentPool<T>&>(*it->second);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::uint32_t m_nextId = 0;
|
||||||
|
std::pmr::unordered_map<std::type_index, std::unique_ptr<IComponentPool>> m_pools;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_ENTITYREGISTRY_H
|
||||||
5
engine/src/ecs/EntitySystem.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EntitySystem.h"
|
||||||
18
engine/src/ecs/EntitySystem.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ENTITYSYSTEM_H
|
||||||
|
#define COLORRACE_ENTITYSYSTEM_H
|
||||||
|
#include "EntityRegistry.h"
|
||||||
|
|
||||||
|
|
||||||
|
class EntitySystem {
|
||||||
|
public:
|
||||||
|
virtual ~EntitySystem() = default;
|
||||||
|
|
||||||
|
virtual void update(engine::EntityRegistry& registry, float deltaTime) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_ENTITYSYSTEM_H
|
||||||
16
engine/src/ecs/standardComponents/HighlightComponent.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_HIGHLIGHTCOMPONENT_H
|
||||||
|
#define COLORRACE_HIGHLIGHTCOMPONENT_H
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct HighlightComponent {
|
||||||
|
glm::vec3 highlightColor;
|
||||||
|
float intensity;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_HIGHLIGHTCOMPONENT_H
|
||||||
16
engine/src/ecs/standardComponents/MeshComponent.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_MESHCOMPONENT_H
|
||||||
|
#define COLORRACE_MESHCOMPONENT_H
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "loader/models/Model.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct MeshComponent {
|
||||||
|
std::shared_ptr<Model> model;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_MESHCOMPONENT_H
|
||||||
15
engine/src/ecs/standardComponents/PickableComponent.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_PICKABLECOMPONENT_H
|
||||||
|
#define COLORRACE_PICKABLECOMPONENT_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct PickableComponent {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_PICKABLECOMPONENT_H
|
||||||
28
engine/src/ecs/standardComponents/TransformComponent.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_TRANSFORMCOMPONENT_H
|
||||||
|
#define COLORRACE_TRANSFORMCOMPONENT_H
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct TransformComponent {
|
||||||
|
glm::vec3 m_position;
|
||||||
|
glm::vec3 m_rotation;
|
||||||
|
glm::vec3 m_scale;
|
||||||
|
|
||||||
|
[[nodiscard]] glm::mat4 computeModelMatrix() const {
|
||||||
|
auto modelMatrix = glm::mat4(1.0f);
|
||||||
|
modelMatrix = glm::translate(modelMatrix, m_position);
|
||||||
|
modelMatrix = glm::rotate(modelMatrix, glm::radians(m_rotation.x), {1.0f, 0.0f, 0.0f});
|
||||||
|
modelMatrix = glm::rotate(modelMatrix, glm::radians(m_rotation.y), {0.0f, 1.0f, 0.0f});
|
||||||
|
modelMatrix = glm::rotate(modelMatrix, glm::radians(m_rotation.z), {0.0f, 0.0f, 1.0f});
|
||||||
|
modelMatrix = glm::scale(modelMatrix, m_scale);
|
||||||
|
return modelMatrix;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_TRANSFORMCOMPONENT_H
|
||||||
27
engine/src/ecs/systems/PickingSystem.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PickingSystem.h"
|
||||||
|
|
||||||
|
std::pair<glm::vec3, glm::vec3> engine::PickingSystem::screenToRay(const glm::vec2 &ndc, const Camera &camera) {
|
||||||
|
glm::mat4 invVP = glm::inverse(camera.getProjectionMatrix() * camera.getViewMatrix());
|
||||||
|
glm::vec4 nearPoint = invVP * glm::vec4(ndc.x, ndc.y, -1.0f, 1.0f); // Y invertiert (Screen vs. NDC)
|
||||||
|
glm::vec4 farPoint = invVP * glm::vec4(ndc.x, ndc.y, 1.0f, 1.0f);
|
||||||
|
nearPoint /= nearPoint.w;
|
||||||
|
farPoint /= farPoint.w;
|
||||||
|
auto origin = glm::vec3(nearPoint);
|
||||||
|
glm::vec3 dir = glm::normalize(glm::vec3(farPoint) - glm::vec3(nearPoint));
|
||||||
|
return {origin, dir};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::PickingSystem::raySphereIntersect(const glm::vec3 &origin, const glm::vec3 &dir, const glm::vec3 ¢er,
|
||||||
|
float radius, float &t) {
|
||||||
|
glm::vec3 oc = origin - center;
|
||||||
|
float b = glm::dot(oc, dir);
|
||||||
|
float c = glm::dot(oc, oc) - radius * radius;
|
||||||
|
float discriminant = b * b - c;
|
||||||
|
if (discriminant < 0.0f) return false;
|
||||||
|
t = -b - std::sqrt(discriminant);
|
||||||
|
return t >= 0.0f;
|
||||||
|
}
|
||||||
66
engine/src/ecs/systems/PickingSystem.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_PICKINGSYSTEM_H
|
||||||
|
#define COLORRACE_PICKINGSYSTEM_H
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "core/inputsOutputs/inputs/Mouse.h"
|
||||||
|
#include "core/inputsOutputs/inputs/MouseButton.h"
|
||||||
|
#include "ecs/EntityRegistry.h"
|
||||||
|
#include "ecs/standardComponents/PickableComponent.h"
|
||||||
|
#include "ecs/standardComponents/TransformComponent.h"
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ecs/standardComponents/MeshComponent.h"
|
||||||
|
|
||||||
|
#include "renderer/entities/Camera.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Mouse;
|
||||||
|
|
||||||
|
class PickingSystem {
|
||||||
|
public:
|
||||||
|
explicit PickingSystem(Camera& camera) : m_camera(camera) {}
|
||||||
|
|
||||||
|
std::optional<Entity> update(const Mouse& mouse, EntityRegistry& registry) {
|
||||||
|
|
||||||
|
//if (ImGui::GetIO().WantCaptureMouse) return std::nullopt;
|
||||||
|
if (!mouse.isClickEvent(MouseButton::LEFT)) return std::nullopt;
|
||||||
|
auto [origin, dir] = screenToRay(mouse.getXY(/*ndc=*/true), m_camera);
|
||||||
|
|
||||||
|
float closestT = std::numeric_limits<float>::max();
|
||||||
|
std::optional<Entity> hit;
|
||||||
|
|
||||||
|
for (const auto& [entity, pickable] : registry.getPool<PickableComponent>()) {
|
||||||
|
const auto transform = registry.getComponent<TransformComponent>(entity);
|
||||||
|
const auto mesh = registry.getComponent<MeshComponent>(entity);
|
||||||
|
|
||||||
|
AABB transformedAABB = mesh.model->getAABB().transformed(transform.computeModelMatrix());
|
||||||
|
Ray ray = Ray(origin, dir);
|
||||||
|
std::optional<RayHit> ray_hit = transformedAABB.intersects(ray, closestT);
|
||||||
|
if (ray_hit.has_value()) {
|
||||||
|
spdlog::info(std::format("Hit: {} {}", entity.value(), std::to_string(ray_hit.value().distance)));
|
||||||
|
closestT = ray_hit.value().distance;
|
||||||
|
hit = entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<glm::vec3, glm::vec3> screenToRay(const glm::vec2& screenPos, const Camera& camera);
|
||||||
|
|
||||||
|
static bool raySphereIntersect(const glm::vec3& origin, const glm::vec3& dir, const glm::vec3& center, float radius, float& t);
|
||||||
|
private:
|
||||||
|
Camera& m_camera;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_PICKINGSYSTEM_H
|
||||||
5
engine/src/game/GameMode.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "GameMode.h"
|
||||||
28
engine/src/game/GameMode.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_GAMEMODE_H
|
||||||
|
#define COLORRACE_GAMEMODE_H
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "GameState.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
template <typename Command, typename Event, typename State>
|
||||||
|
class GameMode {
|
||||||
|
public:
|
||||||
|
static_assert(std::is_base_of_v<GameState, State>, "State must be derived from GameState");
|
||||||
|
|
||||||
|
virtual ~GameMode() = default;
|
||||||
|
|
||||||
|
virtual void sendCommand(const Command& command) = 0;
|
||||||
|
virtual std::vector<Event> pollEvents() = 0;
|
||||||
|
[[nodiscard]] virtual const State& getState() const = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_GAMEMODE_H
|
||||||
5
engine/src/game/GameState.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "GameState.h"
|
||||||
17
engine/src/game/GameState.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_GAMESTATE_H
|
||||||
|
#define COLORRACE_GAMESTATE_H
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class GameState {
|
||||||
|
public:
|
||||||
|
virtual ~GameState() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_GAMESTATE_H
|
||||||
5
engine/src/game/TurnBasedGameMode.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "TurnBasedGameMode.h"
|
||||||
33
engine/src/game/TurnBasedGameMode.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 02.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_TURNBASEDGAMEMODE_H
|
||||||
|
#define COLORRACE_TURNBASEDGAMEMODE_H
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "GameMode.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
using PlayerID = uint32_t;
|
||||||
|
|
||||||
|
template<typename Command, typename Event, typename State>
|
||||||
|
class TurnBasedGameMode : public GameMode<Command, Event, State> {
|
||||||
|
public:
|
||||||
|
explicit TurnBasedGameMode(std::vector<PlayerID> playerOrder) : m_playerOrder(std::move(playerOrder)) {}
|
||||||
|
[[nodiscard]] PlayerID getCurrentPlayer() const { return m_playerOrder[m_currentPlayerIndex]; }
|
||||||
|
[[nodiscard]] bool isCurrentPlayer(PlayerID playerID) const { return getCurrentPlayer() == playerID; }
|
||||||
|
[[nodiscard]] std::vector<PlayerID> getPlayerOrder() const { return m_playerOrder; }
|
||||||
|
protected:
|
||||||
|
void endTurn(bool extraTurn = false) {
|
||||||
|
if (!extraTurn) m_currentPlayerIndex = (m_currentPlayerIndex + 1) % m_playerOrder.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<PlayerID> m_playerOrder;
|
||||||
|
size_t m_currentPlayerIndex = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_TURNBASEDGAMEMODE_H
|
||||||
53
engine/src/layer/DebugLayer.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DebugLayer.h"
|
||||||
|
|
||||||
|
#include "ecs/standardComponents/MeshComponent.h"
|
||||||
|
#include "ecs/standardComponents/PickableComponent.h"
|
||||||
|
#include "ecs/standardComponents/TransformComponent.h"
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "renderer/RenderQueue.h"
|
||||||
|
#include "renderer/primitives/SphereFactory.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
|
||||||
|
void engine::DebugLayer::onUpdate(float deltaTime) {
|
||||||
|
Layer::onUpdate(deltaTime);
|
||||||
|
if (getKeyboard().isKeyDown(GLFW_KEY_H)) {
|
||||||
|
m_showDebugInfo = !m_showDebugInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::DebugLayer::onRender() {
|
||||||
|
Layer::onRender();
|
||||||
|
if (m_showDebugInfo) {
|
||||||
|
auto pickablePool = m_entityRegistry.getPool<PickableComponent>();
|
||||||
|
auto transforms = m_entityRegistry.getPool<engine::TransformComponent>();
|
||||||
|
for (auto& [entity, pickableComponent] : pickablePool) {
|
||||||
|
if (transforms.has(entity)) {
|
||||||
|
auto meshComponent = m_entityRegistry.getComponent<engine::MeshComponent>(entity);
|
||||||
|
glm::vec3 halfExtent = meshComponent.model.get()->getAABB().getHalfExtent();
|
||||||
|
//spdlog::info(std::to_string(halfExtent.x) + " " + std::to_string(halfExtent.y) + " " + std::to_string(halfExtent.z));
|
||||||
|
|
||||||
|
AABB transformedAABB = meshComponent.model->getAABB().transformed(transforms.get(entity).computeModelMatrix());
|
||||||
|
const auto sphereTransformComp = TransformComponent(transforms.get(entity).m_position, {0,0,0}, transformedAABB.getHalfExtent());
|
||||||
|
glm::mat4 modelMatrix = sphereTransformComp.computeModelMatrix();
|
||||||
|
|
||||||
|
RenderCommand renderCommand(m_sphereModel, modelMatrix);
|
||||||
|
m_renderQueue.submit(renderCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_debugRenderer.render(m_renderQueue, m_camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::DebugLayer::onAttachImpl() {
|
||||||
|
Layer::onAttachImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::DebugLayer::onDetachImpl() {
|
||||||
|
Layer::onDetachImpl();
|
||||||
|
}
|
||||||
40
engine/src/layer/DebugLayer.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 04.08.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_DEBUGLAYER_H
|
||||||
|
#define COLORRACE_DEBUGLAYER_H
|
||||||
|
#include "Layer.h"
|
||||||
|
#include "renderer/DebugRenderer.h"
|
||||||
|
#include "renderer/RenderQueue.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Model;
|
||||||
|
|
||||||
|
class DebugLayer: public Layer {
|
||||||
|
public:
|
||||||
|
DebugLayer(engine::EventBus<animation::AnimationMarkerEvent>& animationEventbus, Camera& camera, engine::EntityRegistry& registry, Keyboard &keyboard, Mouse &mouse, std::shared_ptr<Model> sphereModel)
|
||||||
|
: Layer(keyboard, mouse, animationEventbus), m_entityRegistry(registry), m_sphereModel(std::move(sphereModel)), m_camera(camera) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUpdate(float deltaTime) override;
|
||||||
|
void onRender() override;
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void onAttachImpl() override;
|
||||||
|
void onDetachImpl() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
engine::EntityRegistry& m_entityRegistry;
|
||||||
|
bool m_showDebugInfo = true;
|
||||||
|
|
||||||
|
std::shared_ptr<engine::Model> m_sphereModel;
|
||||||
|
RenderQueue m_renderQueue;
|
||||||
|
DebugRenderer m_debugRenderer;
|
||||||
|
|
||||||
|
Camera& m_camera;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_DEBUGLAYER_H
|
||||||
17
engine/src/layer/Layer.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Layer.h"
|
||||||
|
|
||||||
|
void engine::Layer::onAttach(InputContextStack &inputStack) {
|
||||||
|
m_inputStack = &inputStack;
|
||||||
|
m_context = std::make_shared<InputContext>();
|
||||||
|
inputStack.push(m_context);
|
||||||
|
onAttachImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Layer::onDetach(InputContextStack &inputStack) {
|
||||||
|
inputStack.pop();
|
||||||
|
onDetachImpl();
|
||||||
|
}
|
||||||
48
engine/src/layer/Layer.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 29.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_LAYER_H
|
||||||
|
#define COLORRACE_LAYER_H
|
||||||
|
#include "core/animation/events/AnimationMarkerEvent.h"
|
||||||
|
#include "core/events/ApplicationEvents.h"
|
||||||
|
#include "core/events/EventBus.h"
|
||||||
|
#include "core/inputsOutputs/context/InputContextStack.h"
|
||||||
|
#include "core/inputsOutputs/inputs/Keyboard.h"
|
||||||
|
#include "core/inputsOutputs/inputs/Mouse.h"
|
||||||
|
#include "ecs/EntityRegistry.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Layer {
|
||||||
|
public:
|
||||||
|
Layer(Keyboard& keyboard, Mouse& mouse, EventBus<animation::AnimationMarkerEvent>& animationEventBus) : m_keyboard(keyboard), m_mouse(mouse), m_animationEventBus(animationEventBus){};
|
||||||
|
Layer(Keyboard& keyboard, Mouse& mouse, EventBus<animation::AnimationMarkerEvent>& animationEventBus, std::shared_ptr<EventBus<ApplicationEvents>> applicationEventBus) : m_keyboard(keyboard), m_mouse(mouse), m_animationEventBus(animationEventBus), m_applicationEventBus(std::move(applicationEventBus)){};
|
||||||
|
virtual ~Layer() = default;
|
||||||
|
void onAttach(InputContextStack& inputStack);
|
||||||
|
void onDetach(InputContextStack& inputStack);
|
||||||
|
virtual void onUpdate(float deltaTime) {}
|
||||||
|
virtual void onRender() {}
|
||||||
|
protected:
|
||||||
|
virtual void onAttachImpl() {}
|
||||||
|
virtual void onDetachImpl() {}
|
||||||
|
std::shared_ptr<InputContext>& getInputContext() { return m_context; }
|
||||||
|
InputContextStack& getInputStack() { return *m_inputStack; }
|
||||||
|
Keyboard& getKeyboard() { return m_keyboard; }
|
||||||
|
Mouse& getMouse() { return m_mouse; }
|
||||||
|
EventBus<animation::AnimationMarkerEvent>& getAnimationEventBus() { return m_animationEventBus; }
|
||||||
|
|
||||||
|
std::shared_ptr<EventBus<ApplicationEvents>> m_applicationEventBus;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<InputContext> m_context;
|
||||||
|
InputContextStack* m_inputStack = nullptr;
|
||||||
|
|
||||||
|
engine::Keyboard& m_keyboard;
|
||||||
|
engine::Mouse& m_mouse;
|
||||||
|
engine::EventBus<animation::AnimationMarkerEvent>& m_animationEventBus;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_LAYER_H
|
||||||
34
engine/src/layer/Scene.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Scene.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "core/inputsOutputs/context/InputContextStack.h"
|
||||||
|
|
||||||
|
void engine::Scene::onUpdate(float deltaTime) {
|
||||||
|
for (const auto& layer : m_layers) {
|
||||||
|
layer->onUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Scene::onRender() {
|
||||||
|
for (const auto& layer : m_layers) {
|
||||||
|
layer->onRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Scene::onRegisterLoadedAsset(LoadedAsset loadedAsset) {
|
||||||
|
std::cout << "Loaded asset: " << std::endl;
|
||||||
|
assetManager->insertAsset(std::move(loadedAsset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::Scene::addLayer(std::unique_ptr<Layer> layer) {
|
||||||
|
layer->onAttach(m_inputStack);
|
||||||
|
m_layers.push_back(std::move(layer));
|
||||||
|
|
||||||
|
}
|
||||||
63
engine/src/layer/Scene.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_SCENE_H
|
||||||
|
#define COLORRACE_SCENE_H
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Layer.h"
|
||||||
|
#include "core/animation/events/AnimationMarkerEvent.h"
|
||||||
|
#include "core/events/ApplicationEvents.h"
|
||||||
|
#include "core/events/EventBus.h"
|
||||||
|
#include "loader/assets/AssetManager.h"
|
||||||
|
#include "loader/assets/AssetRequests.h"
|
||||||
|
#include "loader/assets/LoadedAssets.h"
|
||||||
|
#include "renderer/entities/Camera.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class Keyboard;
|
||||||
|
class Mouse;
|
||||||
|
class InputContextStack;
|
||||||
|
|
||||||
|
class Scene {
|
||||||
|
public:
|
||||||
|
explicit Scene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse):
|
||||||
|
assetManager(std::make_unique<AssetManager>()), m_inputStack(inputStack), m_keyboard(keyboard), m_mouse(mouse), m_applicationEventBus(std::move(applicationEventbus)) {}
|
||||||
|
virtual ~Scene() = default;
|
||||||
|
virtual void onEnter() {}
|
||||||
|
virtual void onExit() {
|
||||||
|
for (const auto& layer : m_layers) {
|
||||||
|
layer->onDetach(m_inputStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUpdate(float deltaTime);
|
||||||
|
void onRender();
|
||||||
|
|
||||||
|
void onRegisterLoadedAsset(LoadedAsset loadedAsset);
|
||||||
|
|
||||||
|
virtual std::vector<AssetRequest> getRequiredAssets() const { return {}; }
|
||||||
|
protected:
|
||||||
|
std::vector<std::unique_ptr<Layer>> m_layers;
|
||||||
|
EventBus<animation::AnimationMarkerEvent>& getAnimationEventBus() { return m_animationMarkerEventBus; }
|
||||||
|
|
||||||
|
void addLayer(std::unique_ptr<Layer> layer);
|
||||||
|
|
||||||
|
engine::EntityRegistry entityRegistry;
|
||||||
|
std::unique_ptr<AssetManager> assetManager;
|
||||||
|
InputContextStack& m_inputStack;
|
||||||
|
|
||||||
|
engine::Keyboard& m_keyboard;
|
||||||
|
engine::Mouse& m_mouse;
|
||||||
|
std::shared_ptr<engine::EventBus<ApplicationEvents>> m_applicationEventBus;
|
||||||
|
private:
|
||||||
|
EventBus<animation::AnimationMarkerEvent> m_animationMarkerEventBus;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_SCENE_H
|
||||||
64
engine/src/layer/SceneManager.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SceneManager.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
void engine::SceneManager::switchTo(std::unique_ptr<Scene> scene, std::function<void()> onSceneLoaded) {
|
||||||
|
onSceneLoaded = std::move(onSceneLoaded);
|
||||||
|
nextScene = std::move(scene);
|
||||||
|
|
||||||
|
std::vector<AssetRequest> requestedAssets = nextScene->getRequiredAssets();
|
||||||
|
spdlog::debug("Requested Assets: {}", requestedAssets.size());
|
||||||
|
|
||||||
|
for (AssetRequest & request : requestedAssets) {
|
||||||
|
assetLoader.scheduleAsset(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
assetLoader.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::SceneManager::update(float deltaTime) {
|
||||||
|
if (nextScene) {
|
||||||
|
auto uploadedAssets = assetLoader.processUploadQueue(2);
|
||||||
|
std::cout << "Uploaded Assets: " << uploadedAssets.size() << std::endl;
|
||||||
|
for (const auto& asset : uploadedAssets) {
|
||||||
|
nextScene->onRegisterLoadedAsset(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assetLoader.getProgress().isDone()) {
|
||||||
|
if (currentScene) {
|
||||||
|
currentScene->onExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentScene = std::move(nextScene);
|
||||||
|
nextScene = nullptr;
|
||||||
|
currentScene->onEnter();
|
||||||
|
|
||||||
|
assetLoader.stop();
|
||||||
|
|
||||||
|
if (onSceneLoaded) {
|
||||||
|
onSceneLoaded();
|
||||||
|
onSceneLoaded = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentScene) {
|
||||||
|
currentScene->onUpdate(deltaTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::SceneManager::render() const {
|
||||||
|
if (currentScene) {
|
||||||
|
currentScene->onRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float engine::SceneManager::getTransitionProgress() const {
|
||||||
|
return assetLoader.getProgress().fraction();
|
||||||
|
}
|
||||||
36
engine/src/layer/SceneManager.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_SCENEMANAGER_H
|
||||||
|
#define COLORRACE_SCENEMANAGER_H
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "core/inputsOutputs/context/InputContextStack.h"
|
||||||
|
#include "loader/AssetLoader.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class SceneManager {
|
||||||
|
public:
|
||||||
|
explicit SceneManager(InputContextStack& inputStack) :m_inputStack(inputStack) {}
|
||||||
|
void switchTo(std::unique_ptr<Scene> scene, std::function<void()> onSceneLoaded = nullptr);
|
||||||
|
void update(float deltaTime);
|
||||||
|
void render() const;
|
||||||
|
~SceneManager() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] float getTransitionProgress() const;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<Scene> currentScene;
|
||||||
|
std::unique_ptr<Scene> nextScene;
|
||||||
|
bool isTransitioning = false;
|
||||||
|
std::function<void()> onSceneLoaded;
|
||||||
|
AssetLoader assetLoader;
|
||||||
|
|
||||||
|
InputContextStack& m_inputStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif //COLORRACE_SCENEMANAGER_H
|
||||||
180
engine/src/loader/AssetLoader.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetLoader.h"
|
||||||
|
|
||||||
|
#include <dr_wav.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "models/ModelImporter.h"
|
||||||
|
#include "models/ModelUploader.h"
|
||||||
|
#include "sounds/SoundUploader.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "textures/TextureImporter.h"
|
||||||
|
#include "textures/TextureUploader.h"
|
||||||
|
|
||||||
|
void engine::AssetLoader::scheduleAsset(const AssetRequest &request) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(pendingMutex);
|
||||||
|
pendingQueue.push(request);
|
||||||
|
++total;
|
||||||
|
}
|
||||||
|
pendingCondition.notify_one();
|
||||||
|
std::visit([]<typename T>(const T& req) -> void {
|
||||||
|
using Type = std::decay_t<T>;
|
||||||
|
if constexpr (std::is_same_v<Type, TextureRequest>) {
|
||||||
|
spdlog::debug("Scheduled Texture Request: {} -> {}", req.name, req.path);
|
||||||
|
} else if constexpr (std::is_same_v<Type, ModelRequest>) {
|
||||||
|
spdlog::debug("Scheduled Model Request: {} -> {}", req.name, req.path);
|
||||||
|
} else if constexpr (std::is_same_v<Type, SoundRequest>) {
|
||||||
|
spdlog::debug("Scheduled Sound Request: {} -> {}", req.name, req.path);
|
||||||
|
}
|
||||||
|
}, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetLoader::start() {
|
||||||
|
if (!running) {
|
||||||
|
running = true;
|
||||||
|
loadingThread = std::thread(&AssetLoader::loadingThreadFunc, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetLoader::stop() {
|
||||||
|
running = false;
|
||||||
|
pendingCondition.notify_all();
|
||||||
|
if (loadingThread.joinable()) {
|
||||||
|
loadingThread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<engine::LoadedAsset> engine::AssetLoader::processUploadQueue(int maxPerFrame) {
|
||||||
|
std::vector<LoadedAsset> result;
|
||||||
|
auto uploadQueue = determineUploadQueue(maxPerFrame);
|
||||||
|
std::cout << "Upload Queue: " << uploadQueue.size() << std::endl;
|
||||||
|
for (const auto& asset : uploadQueue) {
|
||||||
|
std::visit([&result]<typename T0>(T0& rawData) -> void {
|
||||||
|
using T = std::decay_t<T0>;
|
||||||
|
if constexpr (std::is_same_v<T, RawTextureData>) {
|
||||||
|
Texture2D texture = TextureUploader::upload(rawData);
|
||||||
|
result.emplace_back(LoadedTexture{rawData.name, std::make_shared<Texture2D>(std::move(texture))});
|
||||||
|
} else if constexpr (std::is_same_v<T, RawModelBundle>) {
|
||||||
|
std::cout << "Uploading model " << rawData.model.name << std::endl;
|
||||||
|
auto modelAssets = ModelUploader::upload(rawData, rawData.model.splitPolicy);
|
||||||
|
std::cout << "Moddel Assets" << modelAssets.size() << std::endl;
|
||||||
|
result.insert(result.end(), modelAssets.begin(), modelAssets.end());
|
||||||
|
std::cout << "Result size" << result.size() << std::endl;
|
||||||
|
} else if constexpr (std::is_same_v<T, RawSoundData>) {
|
||||||
|
auto soundAsset = SoundUploader::upload(rawData);
|
||||||
|
result.emplace_back(LoadedSound{rawData.name, std::make_shared<audio::SoundBuffer>(std::move(soundAsset))});
|
||||||
|
} else {
|
||||||
|
static_assert(
|
||||||
|
always_false<T>,
|
||||||
|
"Unhandled asset type in AssetLoader::processUploadQueue"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, asset);
|
||||||
|
++loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loaded Assets: " << result.size() << std::endl;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::LoadingProgress engine::AssetLoader::getProgress() const {
|
||||||
|
return {total.load(), loaded.load()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetLoader::loadingThreadFunc() {
|
||||||
|
while (running) {
|
||||||
|
AssetRequest request;
|
||||||
|
{
|
||||||
|
std::unique_lock lock(pendingMutex);
|
||||||
|
pendingCondition.wait(lock, [this] {
|
||||||
|
return !pendingQueue.empty() || !running;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!running && pendingQueue.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request = pendingQueue.front();
|
||||||
|
pendingQueue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
IntermediateAsset result = std::visit([]<typename T0>(T0& req) -> IntermediateAsset {
|
||||||
|
using T = std::decay_t<T0>;
|
||||||
|
if constexpr (std::is_same_v<T, TextureRequest>) {
|
||||||
|
return processTextureRequest(req);
|
||||||
|
} else if constexpr (std::is_same_v<T, ModelRequest>) {
|
||||||
|
return processModelRequest(req);
|
||||||
|
} else if constexpr (std::is_same_v<T, SoundRequest>) {
|
||||||
|
return processSoundRequest(req);
|
||||||
|
} else {
|
||||||
|
static_assert(always_false<T>, "Unhandled asset type in AssetLoader::loadingThreadFunc");
|
||||||
|
}
|
||||||
|
}, request);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard lock(readyMutex);
|
||||||
|
readyQueue.push(std::move(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::RawTextureData engine::AssetLoader::processTextureRequest(const TextureRequest &request) {
|
||||||
|
spdlog::debug("Processing Texture Request: {} -> {}", request.name, request.path);
|
||||||
|
RawTextureData textureData = TextureImporter::import(request.path, request.flipY);
|
||||||
|
textureData.name = request.name;
|
||||||
|
return textureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::RawModelBundle engine::AssetLoader::processModelRequest(const ModelRequest &request) {
|
||||||
|
spdlog::debug("Processing Model Request: {} -> {}", request.name, request.path);
|
||||||
|
RawModelBundle modelData = ModelImporter::importFromFile(request.path, request.splitPolicy);
|
||||||
|
modelData.model.name = request.name;
|
||||||
|
return modelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::RawSoundData engine::AssetLoader::processSoundRequest(const SoundRequest &request) {
|
||||||
|
RawSoundData soundData;
|
||||||
|
unsigned int channels, sampleRate;
|
||||||
|
drwav_uint64 frameCount;
|
||||||
|
|
||||||
|
drwav_int16* pcmData = drwav_open_file_and_read_pcm_frames_s16(
|
||||||
|
request.path.c_str(), &channels, &sampleRate, &frameCount, nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!pcmData) {
|
||||||
|
throw std::runtime_error("Failed to load sound file: " + request.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
soundData.name = request.name;
|
||||||
|
soundData.channels = channels;
|
||||||
|
soundData.sampleRate = sampleRate;
|
||||||
|
soundData.bitsPerSample = 16;
|
||||||
|
size_t dataSize = frameCount * channels * sizeof(drwav_int16);
|
||||||
|
soundData.pcmData.resize(dataSize);
|
||||||
|
std::memcpy(
|
||||||
|
soundData.pcmData.data(),
|
||||||
|
pcmData,
|
||||||
|
dataSize
|
||||||
|
);
|
||||||
|
drwav_free(pcmData, nullptr);
|
||||||
|
|
||||||
|
return soundData;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<engine::IntermediateAsset> engine::AssetLoader::determineUploadQueue(int maxPerFrame) {
|
||||||
|
std::vector<IntermediateAsset> result;
|
||||||
|
std::lock_guard lock(readyMutex);
|
||||||
|
for (int i = 0; i < maxPerFrame && !readyQueue.empty(); ++i) {
|
||||||
|
result.push_back(std::move(readyQueue.front()));
|
||||||
|
readyQueue.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
68
engine/src/loader/AssetLoader.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ASSETLOADER_H
|
||||||
|
#define COLORRACE_ASSETLOADER_H
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <format>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "assets/AssetRequests.h"
|
||||||
|
#include "assets/LoadedAssets.h"
|
||||||
|
#include "assets/RawAssetData.h"
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
struct LoadingProgress {
|
||||||
|
int total;
|
||||||
|
int loaded;
|
||||||
|
float fraction() const {
|
||||||
|
return total > 0 ? static_cast<float>(loaded) / total : 1.f;
|
||||||
|
}
|
||||||
|
bool isDone() const {
|
||||||
|
return loaded >= total;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
inline constexpr bool always_false = false;
|
||||||
|
|
||||||
|
class AssetLoader {
|
||||||
|
public:
|
||||||
|
void scheduleAsset(const AssetRequest& request);
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
std::vector<LoadedAsset> processUploadQueue(int maxPerFrame);
|
||||||
|
LoadingProgress getProgress() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadingThreadFunc();
|
||||||
|
|
||||||
|
static RawTextureData processTextureRequest(const TextureRequest& request);
|
||||||
|
static RawModelBundle processModelRequest(const ModelRequest& request);
|
||||||
|
static RawSoundData processSoundRequest(const SoundRequest& request);
|
||||||
|
std::vector<IntermediateAsset> determineUploadQueue(int maxPerFrame);
|
||||||
|
|
||||||
|
std::queue<AssetRequest> pendingQueue;
|
||||||
|
std::mutex pendingMutex;
|
||||||
|
std::condition_variable pendingCondition;
|
||||||
|
|
||||||
|
std::queue<IntermediateAsset> readyQueue;
|
||||||
|
std::mutex readyMutex;
|
||||||
|
|
||||||
|
std::atomic<int> total{0};
|
||||||
|
std::atomic<int> loaded{0};
|
||||||
|
|
||||||
|
std::thread loadingThread;
|
||||||
|
std::atomic<bool> running{false};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COLORRACE_ASSETLOADER_H
|
||||||
59
engine/src/loader/assets/AssetFormatters.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ASSETFORMATTERS_H
|
||||||
|
#define COLORRACE_ASSETFORMATTERS_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "AssetRequests.h"
|
||||||
|
#include "AssetTypes.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::formatter<engine::AssetRequest>
|
||||||
|
{
|
||||||
|
constexpr auto parse(
|
||||||
|
std::format_parse_context& ctx)
|
||||||
|
{
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto format(
|
||||||
|
const engine::AssetRequest& request,
|
||||||
|
std::format_context& ctx) const
|
||||||
|
{
|
||||||
|
return std::format_to(
|
||||||
|
ctx.out(),
|
||||||
|
"{}",
|
||||||
|
engine::assetRequestToString(request)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::formatter<engine::TextureType>
|
||||||
|
{
|
||||||
|
constexpr auto parse(
|
||||||
|
std::format_parse_context& ctx)
|
||||||
|
{
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto format(
|
||||||
|
engine::TextureType type,
|
||||||
|
std::format_context& ctx) const
|
||||||
|
{
|
||||||
|
return std::format_to(
|
||||||
|
ctx.out(),
|
||||||
|
"{}",
|
||||||
|
engine::toString(type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif //COLORRACE_ASSETFORMATTERS_H
|
||||||
86
engine/src/loader/assets/AssetManager.cpp
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetManager.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
std::shared_ptr<engine::Model> engine::AssetManager::getModel(const std::string &name) const {
|
||||||
|
auto it = m_models.find(name);
|
||||||
|
if (it == m_models.end()) {
|
||||||
|
throw std::runtime_error("Model not found: " + name);
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::AssetManager::hasModel(const std::string &name) const {
|
||||||
|
return m_models.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::insertAsset(LoadedAsset loadedAsset) {
|
||||||
|
std::cout << "Inserting asset: " << std::endl;
|
||||||
|
std::visit([this](const auto& loaded) {
|
||||||
|
using T = std::decay_t<decltype(loaded)>;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, LoadedModel>) {
|
||||||
|
insertModel(loaded.name, loaded.model);
|
||||||
|
} else if constexpr (std::is_same_v<T, LoadedTexture>) {
|
||||||
|
insertTexture(loaded.name, loaded.texture);
|
||||||
|
} else if constexpr (std::is_same_v<T, LoadedSound>) {
|
||||||
|
insertSound(loaded.name, loaded.sound);
|
||||||
|
}
|
||||||
|
}, loadedAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::insertModel(const std::string &name, std::shared_ptr<Model> model) {
|
||||||
|
std::cout << "Inserting model " << name << std::endl;
|
||||||
|
m_models[name] = std::move(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::unloadModel(const std::string &name) {
|
||||||
|
m_models.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<engine::Texture2D> engine::AssetManager::getTexture(const std::string &name) const {
|
||||||
|
auto it = m_textures.find(name);
|
||||||
|
if (it == m_textures.end()) {
|
||||||
|
throw std::runtime_error("Texture not found: " + name);
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::AssetManager::hasTexture(const std::string &name) const {
|
||||||
|
return m_textures.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::insertTexture(const std::string &name, std::shared_ptr<Texture2D> texture) {
|
||||||
|
std::cout << "Inserting texture " << name << std::endl;
|
||||||
|
m_textures[name] = std::move(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::unloadTexture(const std::string &name) {
|
||||||
|
m_textures.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<engine::audio::SoundBuffer> engine::AssetManager::getSound(const std::string &name) const {
|
||||||
|
auto it = m_loadedAssets.find(name);
|
||||||
|
if (it == m_loadedAssets.end()) {
|
||||||
|
throw std::runtime_error("Sound not found: " + name);
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool engine::AssetManager::hasSound(const std::string &name) const {
|
||||||
|
return m_loadedAssets.contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::insertSound(const std::string &name, std::shared_ptr<audio::SoundBuffer> sound) {
|
||||||
|
std::cout << "Inserting sound " << name << std::endl;
|
||||||
|
m_loadedAssets[name] = std::move(sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
void engine::AssetManager::unloadSound(const std::string &name) {
|
||||||
|
m_loadedAssets.erase(name);
|
||||||
|
}
|
||||||
45
engine/src/loader/assets/AssetManager.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef COLORRACE_ASSETMANAGER_H
|
||||||
|
#define COLORRACE_ASSETMANAGER_H
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "LoadedAssets.h"
|
||||||
|
#include "loader/models/Model.h"
|
||||||
|
#include "loader/textures/Texture2D.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
class AssetManager {
|
||||||
|
public:
|
||||||
|
AssetManager() = default;
|
||||||
|
~AssetManager() = default;
|
||||||
|
|
||||||
|
std::shared_ptr<Model> getModel(const std::string& name) const;
|
||||||
|
bool hasModel(const std::string& name) const;
|
||||||
|
void insertAsset(LoadedAsset loadedAsset);
|
||||||
|
void insertModel(const std::string& name, std::shared_ptr<Model> model);
|
||||||
|
void unloadModel(const std::string& name);
|
||||||
|
|
||||||
|
std::shared_ptr<Texture2D> getTexture(const std::string& name) const;
|
||||||
|
bool hasTexture(const std::string& name) const;
|
||||||
|
void insertTexture(const std::string& name, std::shared_ptr<Texture2D> texture);
|
||||||
|
void unloadTexture(const std::string& name);
|
||||||
|
|
||||||
|
std::shared_ptr<audio::SoundBuffer> getSound(const std::string& name) const;
|
||||||
|
bool hasSound(const std::string& name) const;
|
||||||
|
void insertSound(const std::string& name, std::shared_ptr<audio::SoundBuffer> sound);
|
||||||
|
void unloadSound(const std::string& name);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Texture2D>> m_textures;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Model>> m_models;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<audio::SoundBuffer>> m_loadedAssets;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //COLORRACE_ASSETMANAGER_H
|
||||||
50
engine/src/loader/assets/AssetRequests.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Created by sebastian on 30.07.26.
|
||||||
|
//
|
||||||
|
// AssetRequests.cpp
|
||||||
|
|
||||||
|
#include "AssetRequests.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "RawAssetData.h"
|
||||||
|
#include "loader/AssetLoader.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace engine {
|
||||||
|
|
||||||
|
std::string assetRequestToString(
|
||||||
|
const AssetRequest& request)
|
||||||
|
{
|
||||||
|
return std::visit(
|
||||||
|
[](auto const& req)
|
||||||
|
{
|
||||||
|
using Type = std::decay_t<decltype(req)>;
|
||||||
|
|
||||||
|
|
||||||
|
if constexpr(std::is_same_v<Type, TextureRequest>)
|
||||||
|
{
|
||||||
|
return std::format(
|
||||||
|
"TextureRequest{{name='{}', path='{}'}}",
|
||||||
|
req.name,
|
||||||
|
req.path
|
||||||
|
);
|
||||||
|
} else if constexpr(std::is_same_v<Type, ModelRequest>)
|
||||||
|
{
|
||||||
|
return std::format(
|
||||||
|
"ModelRequest{{name='{}', path='{}'}}",
|
||||||
|
req.name,
|
||||||
|
req.path
|
||||||
|
);
|
||||||
|
} else if constexpr(std::is_same_v<Type, SoundRequest>){
|
||||||
|
return std::format(
|
||||||
|
"SoundRequest{{name='{}', path='{}'}}",
|
||||||
|
req.name,
|
||||||
|
req.path);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||