diff --git a/.gitignore b/.gitignore index d9875ce..880e9cf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ .vs/ cmake-build-* - -include/CAE/Generated/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 348c176..1439057 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/lib") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/lib") set(PLUGIN_DIR "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") -set(PATH_VERSION "${PROJECT_SOURCE_DIR}/include/CAE/Generated/Version.hpp") +set(PATH_VERSION "${PROJECT_BINARY_DIR}/include/CAE/Version.hpp") set(TEMPLATE_PATH "${PROJECT_SOURCE_DIR}/cmake/config/Version.hpp.in") add_compile_definitions(PLUGINS_DIR="${PLUGIN_DIR}") @@ -34,64 +34,46 @@ include(MakeDoc) include(ClangTidy) include(ClangFormat) include(CopyAssets) +include(CompileOptions) + +find_package(nlohmann_json QUIET CONFIG) +if (NOT nlohmann_json_FOUND) + include(FetchContent) + FetchContent_Declare( + nlohmann-json + GIT_REPOSITORY "https://github.com/nlohmann/json.git" + GIT_TAG "v3.12.0" + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + FetchContent_MakeAvailable(nlohmann-json) +endif () +find_package(glm QUIET CONFIG) +if (NOT glm_FOUND) + FetchContent_Declare( + glm + GIT_REPOSITORY "https://github.com/g-truc/glm.git" + GIT_TAG 1.0.3 + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + set(GLM_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) + FetchContent_MakeAvailable(glm) +endif () add_subdirectory(modules) add_subdirectory(plugins) add_subdirectory(tests) -include(FetchContent) -FetchContent_Declare( - nlohmann-json - GIT_REPOSITORY "https://github.com/nlohmann/json.git" - GIT_TAG "v3.12.0" - GIT_SHALLOW TRUE - GIT_PROGRESS TRUE -) -FetchContent_MakeAvailable(nlohmann-json) - add_executable(${PROJECT_NAME} ${SOURCES}) add_dependencies(${PROJECT_NAME} cae-modules) -target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include") +target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" "${PROJECT_BINARY_DIR}/include" ${glm_SOURCE_DIR}) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules nlohmann_json::nlohmann_json + glm::glm ) -if (NOT WIN32 AND NOT APPLE) - set(WARNING_FLAGS - -Wall - -Wextra - -Wdeprecated-copy - -Wmisleading-indentation - -Wnull-dereference - -Woverloaded-virtual - -Wpedantic - -Wshadow - -Wsign-conversion - -Wnon-virtual-dtor - -Wunused - -Wcast-align - -Wno-padded - -Wconversion - -Wformat - -Winit-self - -Wmissing-include-dirs - -Wold-style-cast - -Wredundant-decls - -Wswitch-default - -Wundef - ) -else () - if (MSVC) - set(WARNING_FLAGS /W3) - else() - set(WARNING_FLAGS -Wno-error) - endif() -endif() -if (MSVC) - target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS} /O2) -else () - target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS} -O3) -endif () copy_directory_to_target( cae diff --git a/assets/config/default.json b/assets/config/default.json index cd552e5..76c95b7 100644 --- a/assets/config/default.json +++ b/assets/config/default.json @@ -3,6 +3,16 @@ "masterVolume": 0.8, "muted": false }, + "camera": { + "position": [0.0, 0.0, 1.0], + "rotation": [0.0, 0.0, 0.0], + "direction": [0.0, 0.0, -1.0], + "movementSpeed": 2.5, + "rotationSpeed": 7.5, + "fov": 45, + "nearPlane": 0.1, + "farPlane": 1000.0 + }, "log": { "fps": false }, @@ -13,10 +23,7 @@ "renderer": { "vsync": false, "frameRateLimit": 90, - "clearColor": [1.0, 1.0, 1.0, 1.0] - }, - "user": { - "name": "User" + "clearColor": [0.2, 0.2, 0.2, 1.0] }, "window": { "name": "CAE - Cross API Engine", diff --git a/assets/shaders/glsl/texture.frag b/assets/shaders/glsl/texture.frag index 84a4c3e..ffb6c38 100644 --- a/assets/shaders/glsl/texture.frag +++ b/assets/shaders/glsl/texture.frag @@ -1,11 +1,9 @@ #version 450 core -layout(location = 0) in vec2 vUV; +layout(location = 0) in vec3 vColor; layout(location = 0) out vec4 FragColor; -layout(binding = 0) uniform sampler2D uTexture; - void main() { - FragColor = texture(uTexture, vUV); + FragColor = vec4(vColor, 1.0); } diff --git a/assets/shaders/glsl/texture.vert b/assets/shaders/glsl/texture.vert index 38120fc..46a8288 100644 --- a/assets/shaders/glsl/texture.vert +++ b/assets/shaders/glsl/texture.vert @@ -1,12 +1,17 @@ #version 450 core -layout(location = 0) in vec2 aPos; -layout(location = 1) in vec2 aUV; +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aColor; -layout(location = 0) out vec2 vUV; +layout(location = 0) out vec3 vColor; + +layout(set = 0, binding = 0) uniform Matrices +{ + mat4 uMVP; +}; void main() { - gl_Position = vec4(aPos, 0.0, 1.0); - vUV = aUV; + vColor = aColor; + gl_Position = uMVP * vec4(aPos, 1.0); } diff --git a/cmake/modules/CompileOptions.cmake b/cmake/modules/CompileOptions.cmake new file mode 100644 index 0000000..5b0bc68 --- /dev/null +++ b/cmake/modules/CompileOptions.cmake @@ -0,0 +1,113 @@ +add_library(cae-compile-options INTERFACE) + +target_compile_features(cae-compile-options INTERFACE cxx_std_23) + +option(CAE_STRICT_WARNINGS "Enable strict warning level" OFF) +option(CAE_ENABLE_SANITIZERS "Enable address and undefined sanitizers" OFF) +option(CAE_ENABLE_LTO "Enable LTO on final targets" OFF) + +target_compile_options(cae-compile-options INTERFACE + # Strict warnings + $<$,$,$>>: + -Wall + -Wextra + -Wpedantic + -Wshadow + -Wconversion + -Wsign-conversion + -Wold-style-cast + -Woverloaded-virtual + -Wnull-dereference + -Wformat=2 + -Wundef + -Wswitch-default + > + # mobile / web + $<$,$,$>: + -Wall + -Wextra + -Wshadow + -Wsign-conversion + -Wold-style-cast + > + # Default warnings + $<$,$>>: + -Wall + -Wextra + > + # MSVC + $<$: + /W4 + /permissive- + /Zc:__cplusplus + /Zc:preprocessor + > +) + +# GCC / Clang +target_compile_options(cae-compile-options INTERFACE + $<$,$>:-O2> + $<$,$>:-O0 -g> +) + +# MSVC +target_compile_options(cae-compile-options INTERFACE + $<$,$>:/O2> + $<$,$>:/O2 /Zi> + $<$,$>:/Od /Zi> +) + +target_compile_definitions(cae-compile-options INTERFACE + $<$: + CAE_DEBUG + > +) + +if(CAE_ENABLE_SANITIZERS) + target_compile_options(cae-compile-options INTERFACE + $<$,$>>: + -fsanitize=address,undefined + > + ) + target_link_options(cae-compile-options INTERFACE + $<$,$>>: + -fsanitize=address,undefined + > + ) +endif() + +function(cae_enable_lto target) + if (CAE_ENABLE_LTO) + include(CheckIPOSupported) + check_ipo_supported(RESULT CAE_LTO_SUPPORTED OUTPUT CAE_LTO_ERROR) + if (CAE_LTO_SUPPORTED) + set_property(TARGET ${target} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(WARNING "CAE: LTO not supported: ${CAE_LTO_ERROR}") + endif() + endif() +endfunction() + +if (EMSCRIPTEN) + target_compile_definitions(cae-compile-options INTERFACE + CAE_PLATFORM_WEB + CAE_PLATFORM_EMSCRIPTEN + ) +elseif (ANDROID) + target_compile_definitions(cae-compile-options INTERFACE CAE_PLATFORM_ANDROID) +elseif (APPLE) + if (IOS) + target_compile_definitions(cae-compile-options INTERFACE CAE_PLATFORM_IOS) + else() + target_compile_definitions(cae-compile-options INTERFACE CAE_PLATFORM_MACOS) + endif() +elseif (WIN32) + target_compile_definitions(cae-compile-options INTERFACE + CAE_PLATFORM_WINDOWS + NOMINMAX + WIN32_LEAN_AND_MEAN + ) +elseif (UNIX) + target_compile_definitions(cae-compile-options INTERFACE CAE_PLATFORM_LINUX) +endif() + diff --git a/include/CAE/Application.hpp b/include/CAE/Application.hpp index ed6ffe4..9e8b2e7 100644 --- a/include/CAE/Application.hpp +++ b/include/CAE/Application.hpp @@ -50,7 +50,7 @@ namespace cae /// /// @brief Start the application /// - void start() const; + void start(); /// /// @brief Stop the application @@ -75,10 +75,16 @@ namespace cae /// static EngineConfig parseEngineConf(const std::string &path); + /// + /// @brief main loop + /// + void mainLoop(); + std::unique_ptr m_pluginLoader = nullptr; std::unique_ptr m_engine = nullptr; AppConfig m_appConfig; + std::unordered_map m_keyState; }; // class Application diff --git a/include/CAE/Common.hpp b/include/CAE/Common.hpp index f1edb22..934e0c6 100644 --- a/include/CAE/Common.hpp +++ b/include/CAE/Common.hpp @@ -6,7 +6,7 @@ #pragma once -#include "CAE/Generated/Version.hpp" +#include "CAE/Version.hpp" #include "Engine/Common.hpp" @@ -47,6 +47,7 @@ namespace cae namespace WINDOW { + inline constexpr auto COCOA = "Cocoa"; inline constexpr auto GLFW = "GLFW"; inline constexpr auto WIN32_ = "Win32"; inline constexpr auto X11 = "X11"; diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 60e8e7f..44f2461 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(Engine) target_link_libraries(cae-modules INTERFACE cae-utils cae-engine + cae-compile-options ) target_include_directories(cae-modules SYSTEM INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/Interfaces/include" diff --git a/modules/Engine/CMakeLists.txt b/modules/Engine/CMakeLists.txt index 0ce80b0..138bbf4 100644 --- a/modules/Engine/CMakeLists.txt +++ b/modules/Engine/CMakeLists.txt @@ -4,21 +4,6 @@ project(cae-engine LANGUAGES CXX ) -include(FetchContent) - -set(GLM_BUILD_TESTS OFF CACHE INTERNAL "") -set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "") - -FetchContent_Declare( - glm - GIT_REPOSITORY https://github.com/g-truc/glm.git - GIT_TAG 1.0.3 - GIT_SHALLOW TRUE - GIT_PROGRESS TRUE -) - -FetchContent_MakeAvailable(glm) - set(SRC_DIR "${PROJECT_SOURCE_DIR}/src") set(INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include") @@ -36,6 +21,7 @@ target_sources(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE cae-utils + cae-compile-options glm::glm ) target_include_directories(${PROJECT_NAME} @@ -47,8 +33,6 @@ target_include_directories(${PROJECT_NAME} "${CMAKE_SOURCE_DIR}/modules/Interfaces/include" ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_EXTENSIONS OFF diff --git a/modules/Engine/include/Engine/Camera.hpp b/modules/Engine/include/Engine/Camera.hpp index 9c1c779..cef7348 100644 --- a/modules/Engine/include/Engine/Camera.hpp +++ b/modules/Engine/include/Engine/Camera.hpp @@ -8,7 +8,7 @@ #include "Engine/Common.hpp" -#include +#include #include @@ -23,7 +23,14 @@ namespace cae class Camera { public: - Camera() = default; + Camera(const glm::vec3 position, const glm::vec3 rotation, const glm::vec3 direction, + const float moveSpeed = CAMERA::MOVE_SPEED, const float lookSpeed = CAMERA::LOOK_SPEED, + const float fov = CAMERA::FOV, const float nearPlane = CAMERA::NEAR_PLANE, + const float farPlane = CAMERA::FAR_PLANE) + : m_position(position), m_rotation(rotation), m_direction(direction), m_moveSpeed(moveSpeed), + m_lookSpeed(lookSpeed), m_fov(fov), m_near(nearPlane), m_far(farPlane) + { + } ~Camera() = default; Camera(const Camera &) = delete; @@ -51,12 +58,28 @@ namespace cae [[nodiscard]] const float &getNear() const { return m_near; } [[nodiscard]] const float &getFar() const { return m_far; } + [[nodiscard]] glm::mat4 getViewMatrix() const + { + return glm::lookAt(m_position, m_position + m_direction, glm::vec3(0.0F, 1.0F, 0.0F)); + } + [[nodiscard]] glm::mat4 getProjectionMatrix(const float aspectRatio) const + { + return glm::perspective(glm::radians(m_fov), aspectRatio, m_near, m_far); + } + [[nodiscard]] glm::mat4 getViewProjection(const float aspectRatio) const + { + return getProjectionMatrix(aspectRatio) * getViewMatrix(); + } + /// /// @param direction Direction to move the camera /// @param deltaTime Time delta for movement /// @brief Move the camera in a given direction /// - void move(const glm::vec3 &direction, float deltaTime); + void move(const glm::vec3 &direction, const float deltaTime) + { + m_position += direction * m_moveSpeed * deltaTime; + } /// /// @param yawOffset Yaw offset to rotate the camera @@ -64,7 +87,16 @@ namespace cae /// @param deltaTime Time delta for rotation /// @brief Rotate the camera by given yaw and pitch offsets /// - void rotate(float yawOffset, float pitchOffset, float deltaTime); + void rotate(const float yawOffset, const float pitchOffset, const float deltaTime) + { + m_rotation.y += yawOffset * m_lookSpeed * deltaTime; + m_rotation.x += pitchOffset * m_lookSpeed * deltaTime; + + m_rotation.x = std::min(m_rotation.x, 89.0F); + m_rotation.x = std::max(m_rotation.x, -89.0F); + + updateDirectionFromRotation(); + } private: std::string m_name = CAMERA::NAME; @@ -80,6 +112,17 @@ namespace cae float m_near = CAMERA::NEAR_PLANE; float m_far = CAMERA::FAR_PLANE; + void updateDirectionFromRotation() + { + const float yaw = glm::radians(m_rotation.y); + const float pitch = glm::radians(m_rotation.x); + + m_direction.x = cos(pitch) * sin(yaw); + m_direction.y = std::sin(pitch); + m_direction.z = -cos(pitch) * cos(yaw); + m_direction = glm::normalize(m_direction); + } + }; // class Camera } // namespace cae diff --git a/modules/Engine/include/Engine/Common.hpp b/modules/Engine/include/Engine/Common.hpp index 4df2287..79510a9 100644 --- a/modules/Engine/include/Engine/Common.hpp +++ b/modules/Engine/include/Engine/Common.hpp @@ -26,7 +26,7 @@ namespace cae { inline constexpr auto NAME = "Default name"; inline constexpr auto MOVE_SPEED = 2.5F; - inline constexpr auto LOOK_SPEED = 100.F; + inline constexpr auto LOOK_SPEED = 10.0F; inline constexpr auto FOV = 45.F; inline constexpr auto NEAR_PLANE = 0.1F; inline constexpr auto FAR_PLANE = 100.F; diff --git a/modules/Engine/include/Engine/Engine.hpp b/modules/Engine/include/Engine/Engine.hpp index 5b77189..eeedd5b 100644 --- a/modules/Engine/include/Engine/Engine.hpp +++ b/modules/Engine/include/Engine/Engine.hpp @@ -9,12 +9,13 @@ #include "Engine/Camera.hpp" #include "Engine/ShaderManager.hpp" -#include "Interfaces/IAudio.hpp" -#include "Interfaces/INetwork.hpp" -#include "Interfaces/Input/IInput.hpp" +#include "Interfaces/Audio/IAudio.hpp" +#include "Interfaces/Network/INetwork.hpp" #include "Interfaces/Renderer/IRenderer.hpp" #include "Utils/Clock.hpp" +#include + namespace cae { @@ -28,6 +29,15 @@ namespace cae float audio_master_volume = AUDIO::VOLUME; bool audio_muted = AUDIO::MUTED; + glm::vec3 camera_position = glm::vec3(0.0F, 0.0F, 0.0F); + glm::vec3 camera_rotation = glm::vec3(0.0F, 0.0F, 0.0F); + glm::vec3 camera_direction = glm::vec3(0.0F, 0.0F, -1.0F); + float camera_move_speed = CAMERA::MOVE_SPEED; + float camera_look_speed = CAMERA::LOOK_SPEED; + float camera_fov = CAMERA::FOV; + float camera_near_plane = CAMERA::NEAR_PLANE; + float camera_far_plane = CAMERA::FAR_PLANE; + bool log_fps = LOG::LOG_FPS; std::string network_host = NETWORK::HOST; @@ -57,7 +67,6 @@ namespace cae public: Engine(const EngineConfig &config, const std::function()> &audioFactory, - const std::function()> &inputFactory, const std::function()> &networkFactory, const std::function()> &rendererFactory, const std::function()> &shaderIRFactory, @@ -71,12 +80,12 @@ namespace cae Engine &operator=(Engine &&) = delete; [[nodiscard]] const std::shared_ptr &getAudio() const { return m_audioPlugin; } - [[nodiscard]] const std::shared_ptr &getInput() const { return m_inputPlugin; } [[nodiscard]] const std::shared_ptr &getNetwork() const { return m_networkPlugin; } [[nodiscard]] const std::shared_ptr &getRenderer() const { return m_rendererPlugin; } [[nodiscard]] const std::shared_ptr &getWindow() const { return m_windowPlugin; } [[nodiscard]] const std::unique_ptr &getClock() { return m_clock; } + [[nodiscard]] const std::unique_ptr &getShaderManager() const { return m_shaderManager; } [[nodiscard]] const std::unique_ptr &getCamera() const { return m_camera; } /// @@ -88,9 +97,16 @@ namespace cae const std::vector &vertices) const; /// - /// @brief Run the engine main loop + /// @param fpsBuffer + /// @param fpsIndex + /// @brief + /// + void update(std::array &fpsBuffer, int &fpsIndex); + + /// + /// @brief /// - void run() const; + void render(); /// /// @brief Stop the engine @@ -99,7 +115,6 @@ namespace cae private: std::shared_ptr m_audioPlugin = nullptr; - std::shared_ptr m_inputPlugin = nullptr; std::shared_ptr m_networkPlugin = nullptr; std::shared_ptr m_rendererPlugin = nullptr; std::shared_ptr m_windowPlugin = nullptr; diff --git a/modules/Engine/include/Engine/ShaderManager.hpp b/modules/Engine/include/Engine/ShaderManager.hpp index 090dafd..7f1a258 100644 --- a/modules/Engine/include/Engine/ShaderManager.hpp +++ b/modules/Engine/include/Engine/ShaderManager.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/Shader/IShaderIR.hpp" +#include "Interfaces/Shader/IR/IShaderIR.hpp" #include diff --git a/modules/Engine/src/engine.cpp b/modules/Engine/src/engine.cpp index 3881032..4268adf 100644 --- a/modules/Engine/src/engine.cpp +++ b/modules/Engine/src/engine.cpp @@ -1,32 +1,33 @@ #include "Engine/Engine.hpp" #include "Utils/Logger.hpp" +#include "Utils/Path.hpp" #include #include -#include "Utils/Path.hpp" - void printFps(std::array &fpsBuffer, int &fpsIndex, const float deltaTime) { fpsBuffer[fpsIndex % 10] = 1.0F / deltaTime; fpsIndex++; - float avgFps = std::accumulate(fpsBuffer.begin(), fpsBuffer.end(), 0.0f) / 10.0f; + float avgFps = std::accumulate(fpsBuffer.begin(), fpsBuffer.end(), 0.0F) / 10.0F; utl::Logger::log(std::format("FPS: {}", avgFps), utl::LogLevel::INFO); } cae::Engine::Engine(const EngineConfig &config, const std::function()> &audioFactory, - const std::function()> &inputFactory, const std::function()> &networkFactory, const std::function()> &rendererFactory, const std::function()> &shaderIRFactory, const std::vector()>> &shaderFrontendFactories, const std::function()> &windowFactory) - : m_audioPlugin(audioFactory()), m_inputPlugin(inputFactory()), m_networkPlugin(networkFactory()), - m_rendererPlugin(rendererFactory()), m_windowPlugin(windowFactory()), m_clock(std::make_unique()), + : m_audioPlugin(audioFactory()), m_networkPlugin(networkFactory()), m_rendererPlugin(rendererFactory()), + m_windowPlugin(windowFactory()), m_clock(std::make_unique()), m_shaderManager(std::make_unique(shaderFrontendFactories, shaderIRFactory)), - m_camera(std::make_unique()), m_logFps(config.log_fps) + m_camera(std::make_unique(config.camera_position, config.camera_rotation, config.camera_direction, + config.camera_move_speed, config.camera_look_speed, config.camera_fov, + config.camera_near_plane, config.camera_far_plane)), + m_logFps(config.log_fps) { constexpr auto boolToStr = [](const bool b) { return b ? "true" : "false"; }; std::ostringstream msg; @@ -58,20 +59,23 @@ void cae::Engine::initializeRenderResources(const std::vector m_rendererPlugin->createMesh(vertices); } -void cae::Engine::run() const +void cae::Engine::render() +{ + constexpr auto model = glm::mat4(1.0F); + + const glm::mat4 mvp = m_camera->getViewProjection(static_cast(m_windowPlugin->getWindowSize().width) / + m_windowPlugin->getWindowSize().height) * + model; + m_rendererPlugin->draw(m_windowPlugin->getWindowSize(), "basic", mvp); +} + +void cae::Engine::update(std::array &fpsBuffer, int &fpsIndex) { - std::array fpsBuffer{}; - int fpsIndex = 0; - while (!m_windowPlugin->shouldClose()) + if (m_logFps) { - m_rendererPlugin->draw(m_windowPlugin->getWindowSize(), "basic"); - m_windowPlugin->pollEvents(); - if (m_logFps) - { - printFps(fpsBuffer, fpsIndex, m_clock->getDeltaSeconds()); - } - m_clock->restart(); + printFps(fpsBuffer, fpsIndex, m_clock->getDeltaSeconds()); } + m_clock->restart(); } void cae::Engine::stop() @@ -80,10 +84,13 @@ void cae::Engine::stop() m_windowPlugin->close(); m_audioPlugin = nullptr; - m_inputPlugin = nullptr; m_networkPlugin = nullptr; m_rendererPlugin = nullptr; m_windowPlugin = nullptr; + + m_clock = nullptr; + m_shaderManager = nullptr; + m_camera = nullptr; } void cae::Engine::initWindow(const std::string &windowName, const WindowSize &windowSize, diff --git a/modules/Interfaces/include/Interfaces/Audio/AAudio.hpp b/modules/Interfaces/include/Interfaces/Audio/AAudio.hpp new file mode 100644 index 0000000..b0c2df1 --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Audio/AAudio.hpp @@ -0,0 +1,27 @@ +/// +/// @file IAudio.hpp +/// @brief This file contains the audio abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Audio/IAudio.hpp" + +namespace cae +{ + + /// + /// @interface AAudio + /// @brief Abstract class for audio + /// @namespace cae + /// + class AAudio : public IAudio + { + + public: + ~AAudio() override = default; + + }; // interface AAudio + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/IAudio.hpp b/modules/Interfaces/include/Interfaces/Audio/IAudio.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/IAudio.hpp rename to modules/Interfaces/include/Interfaces/Audio/IAudio.hpp diff --git a/modules/Interfaces/include/Interfaces/Input/Key/Keyboard.hpp b/modules/Interfaces/include/Interfaces/Input/Key/Keyboard.hpp index 8c9f8ea..e118894 100644 --- a/modules/Interfaces/include/Interfaces/Input/Key/Keyboard.hpp +++ b/modules/Interfaces/include/Interfaces/Input/Key/Keyboard.hpp @@ -116,6 +116,10 @@ namespace cae NumLock, ScrollLock, + PrintScreen, + Pause, + Menu, + Count }; } // namespace cae diff --git a/modules/Interfaces/include/Interfaces/Input/Key/Mouse.hpp b/modules/Interfaces/include/Interfaces/Input/Key/Mouse.hpp index ee774ef..1e98e7e 100644 --- a/modules/Interfaces/include/Interfaces/Input/Key/Mouse.hpp +++ b/modules/Interfaces/include/Interfaces/Input/Key/Mouse.hpp @@ -18,6 +18,7 @@ namespace cae XButton1, XButton2, WheelUp, - WheelDown + WheelDown, + Count }; } // namespace cae diff --git a/modules/Interfaces/include/Interfaces/Model/AModel.hpp b/modules/Interfaces/include/Interfaces/Model/AModel.hpp new file mode 100644 index 0000000..fad0d4f --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Model/AModel.hpp @@ -0,0 +1,27 @@ +/// +/// @file AModel.hpp +/// @brief This file contains the model abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Model/IModel.hpp" + +namespace cae +{ + + /// + /// @interface AModel + /// @brief Abstract class for model + /// @namespace cae + /// + class AModel : public IModel + { + + public: + ~AModel() override = default; + + }; // interface AModel + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/IModel.hpp b/modules/Interfaces/include/Interfaces/Model/IModel.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/IModel.hpp rename to modules/Interfaces/include/Interfaces/Model/IModel.hpp diff --git a/modules/Interfaces/include/Interfaces/Network/ANetwork.hpp b/modules/Interfaces/include/Interfaces/Network/ANetwork.hpp new file mode 100644 index 0000000..95e75d1 --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Network/ANetwork.hpp @@ -0,0 +1,27 @@ +/// +/// @file ANetwork.hpp +/// @brief This file contains the network abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Network/INetwork.hpp" + +namespace cae +{ + + /// + /// @interface ANetwork + /// @brief Abstract class for network + /// @namespace cae + /// + class ANetwork : public INetwork + { + + public: + ~ANetwork() override = default; + + }; // interface ANetwork + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/INetwork.hpp b/modules/Interfaces/include/Interfaces/Network/INetwork.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/INetwork.hpp rename to modules/Interfaces/include/Interfaces/Network/INetwork.hpp diff --git a/modules/Interfaces/include/Interfaces/Physic/APhysic.hpp b/modules/Interfaces/include/Interfaces/Physic/APhysic.hpp new file mode 100644 index 0000000..2d32105 --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Physic/APhysic.hpp @@ -0,0 +1,27 @@ +/// +/// @file APhysic.hpp +/// @brief This file contains the physic abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Physic/IPhysic.hpp" + +namespace cae +{ + + /// + /// @interface APhysic + /// @brief Abstract class for physic + /// @namespace cae + /// + class APhysic : public IPhysic + { + + public: + ~APhysic() override = default; + + }; // interface APhysic + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/IPhysic.hpp b/modules/Interfaces/include/Interfaces/Physic/IPhysic.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/IPhysic.hpp rename to modules/Interfaces/include/Interfaces/Physic/IPhysic.hpp diff --git a/modules/Interfaces/include/Interfaces/Renderer/ARenderer.hpp b/modules/Interfaces/include/Interfaces/Renderer/ARenderer.hpp index 4183b16..cf2192b 100644 --- a/modules/Interfaces/include/Interfaces/Renderer/ARenderer.hpp +++ b/modules/Interfaces/include/Interfaces/Renderer/ARenderer.hpp @@ -22,9 +22,6 @@ namespace cae public: ~ARenderer() override = default; - protected: - - private: }; // interface ARenderer } // namespace cae diff --git a/modules/Interfaces/include/Interfaces/Renderer/IRenderer.hpp b/modules/Interfaces/include/Interfaces/Renderer/IRenderer.hpp index 0332af3..fce1988 100644 --- a/modules/Interfaces/include/Interfaces/Renderer/IRenderer.hpp +++ b/modules/Interfaces/include/Interfaces/Renderer/IRenderer.hpp @@ -6,8 +6,10 @@ #pragma once -#include "Interfaces/IWindow.hpp" -#include "Interfaces/Shader/IShaderFrontend.hpp" +#include "Interfaces/Shader/Frontend/IShaderFrontend.hpp" +#include "Interfaces/Window/IWindow.hpp" + +#include namespace cae { @@ -74,9 +76,10 @@ namespace cae /// /// @param windowSize Current window size /// @param shaderId Shader ID to use for drawing + /// @param mvp Model-View-Projection matrix /// @brief Draw the scene using the specified shader and window size /// - virtual void draw(const WindowSize &windowSize, const ShaderID &shaderId) = 0; + virtual void draw(const WindowSize &windowSize, const ShaderID &shaderId, glm::mat4 mvp) = 0; /// /// @param vertices Vertex data to create the mesh diff --git a/modules/Interfaces/include/Interfaces/Shader/Frontend/AShaderFrontend.hpp b/modules/Interfaces/include/Interfaces/Shader/Frontend/AShaderFrontend.hpp new file mode 100644 index 0000000..9a2c9bd --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Shader/Frontend/AShaderFrontend.hpp @@ -0,0 +1,27 @@ +/// +/// @file AShaderFrontend.hpp +/// @brief This file contains the ShaderFrontend abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Shader/Frontend/IShaderFrontend.hpp" + +namespace cae +{ + + /// + /// @interface AShaderFrontend + /// @brief Abstract class for shader frontend + /// @namespace cae + /// + class AShaderFrontend : public IShaderFrontend + { + + public: + ~AShaderFrontend() override = default; + + }; // interface AShaderFrontend + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/Shader/IShaderFrontend.hpp b/modules/Interfaces/include/Interfaces/Shader/Frontend/IShaderFrontend.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/Shader/IShaderFrontend.hpp rename to modules/Interfaces/include/Interfaces/Shader/Frontend/IShaderFrontend.hpp diff --git a/modules/Interfaces/include/Interfaces/Shader/IR/AShaderIR.hpp b/modules/Interfaces/include/Interfaces/Shader/IR/AShaderIR.hpp new file mode 100644 index 0000000..6f57023 --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Shader/IR/AShaderIR.hpp @@ -0,0 +1,27 @@ +/// +/// @file AShaderIR.hpp +/// @brief This file contains the ShaderIR abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Shader/IR/IShaderIR.hpp" + +namespace cae +{ + + /// + /// @interface AShaderIR + /// @brief Abstract class for shader IR + /// @namespace cae + /// + class AShaderIR : public IShaderIR + { + + public: + ~AShaderIR() override = default; + + }; // interface AShaderIR + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/Shader/IShaderIR.hpp b/modules/Interfaces/include/Interfaces/Shader/IR/IShaderIR.hpp similarity index 96% rename from modules/Interfaces/include/Interfaces/Shader/IShaderIR.hpp rename to modules/Interfaces/include/Interfaces/Shader/IR/IShaderIR.hpp index 3fde505..1d4551e 100644 --- a/modules/Interfaces/include/Interfaces/Shader/IShaderIR.hpp +++ b/modules/Interfaces/include/Interfaces/Shader/IR/IShaderIR.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/Shader/IShaderFrontend.hpp" +#include "Interfaces/Shader/Frontend/IShaderFrontend.hpp" #include #include diff --git a/modules/Interfaces/include/Interfaces/UI/AUI.hpp b/modules/Interfaces/include/Interfaces/UI/AUI.hpp new file mode 100644 index 0000000..27f1394 --- /dev/null +++ b/modules/Interfaces/include/Interfaces/UI/AUI.hpp @@ -0,0 +1,27 @@ +/// +/// @file AUI.hpp +/// @brief This file contains the ui abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/UI/IUI.hpp" + +namespace cae +{ + + /// + /// @interface AUI + /// @brief Abstract class for ui + /// @namespace cae + /// + class AUI : public IUI + { + + public: + ~AUI() override = default; + + }; // interface AUI + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/IUI.hpp b/modules/Interfaces/include/Interfaces/UI/IUI.hpp similarity index 100% rename from modules/Interfaces/include/Interfaces/IUI.hpp rename to modules/Interfaces/include/Interfaces/UI/IUI.hpp diff --git a/modules/Interfaces/include/Interfaces/Window/AWindow.hpp b/modules/Interfaces/include/Interfaces/Window/AWindow.hpp new file mode 100644 index 0000000..b42faec --- /dev/null +++ b/modules/Interfaces/include/Interfaces/Window/AWindow.hpp @@ -0,0 +1,27 @@ +/// +/// @file AWindow.hpp +/// @brief This file contains the Window abstract class +/// @namespace cae +/// + +#pragma once + +#include "Interfaces/Window/IWindow.hpp" + +namespace cae +{ + + /// + /// @interface IWindow + /// @brief Abstract class for window + /// @namespace cae + /// + class AWindow : public IWindow + { + + public: + ~AWindow() override = default; + + }; // interface AWindow + +} // namespace cae diff --git a/modules/Interfaces/include/Interfaces/IWindow.hpp b/modules/Interfaces/include/Interfaces/Window/IWindow.hpp similarity index 62% rename from modules/Interfaces/include/Interfaces/IWindow.hpp rename to modules/Interfaces/include/Interfaces/Window/IWindow.hpp index 4b261a3..e04a192 100644 --- a/modules/Interfaces/include/Interfaces/IWindow.hpp +++ b/modules/Interfaces/include/Interfaces/Window/IWindow.hpp @@ -6,6 +6,9 @@ #pragma once +#include "Interfaces/Input/Key/Keyboard.hpp" +#include "Interfaces/Input/Key/Mouse.hpp" + #include "Utils/Interfaces/IPlugin.hpp" namespace cae @@ -33,6 +36,58 @@ namespace cae void *display; }; + /// + /// @enum WindowEventType + /// @brief Enum for window event types + /// @namespace cae + /// + enum class WindowEventType : uint8_t + { + KeyDown, + KeyUp, + MouseMove, + MouseButtonDown, + MouseButtonUp, + MouseScroll, + Resize, + Focus, + Close + }; + + /// + /// @struct WindowEvent + /// @brief Struct for window events + /// @namespace cae + /// + struct WindowEvent + { + WindowEventType type; + + union + { + struct + { + KeyCode key; + } key; + struct + { + int x, y; + } mouseMove; + struct + { + MouseButton button; + } mouseButton; + struct + { + float x, y; + } scroll; + struct + { + uint16_t w, h; + } resize; + }; + }; + /// /// @interface IWindow /// @brief Interface for window @@ -74,7 +129,7 @@ namespace cae /// @return True if the icon was set successfully /// @brief Set the window icon from the given image path /// - virtual bool setIcon(const std::string &path) const = 0; + virtual void setIcon(const std::string &path) const = 0; /// /// @return True if the window should close @@ -87,6 +142,13 @@ namespace cae /// virtual void pollEvents() = 0; + /// + /// @param outEvent Event to be filled + /// @return True if an event was polled + /// @brief Poll window events into outEvent + /// + virtual bool pollEvent(WindowEvent &outEvent) = 0; + /// /// @return True if the window was resized /// @brief Check if the window was resized @@ -101,9 +163,6 @@ namespace cae // virtual bool isFullScreen() const = 0; // virtual void setFullScreen(bool fullScreen) const = 0; - private: - // std::unique_ptr m_inputManager; - }; // interface IWindow } // namespace cae diff --git a/modules/Utils/CMakeLists.txt b/modules/Utils/CMakeLists.txt index af82eb4..0add7fe 100644 --- a/modules/Utils/CMakeLists.txt +++ b/modules/Utils/CMakeLists.txt @@ -29,6 +29,10 @@ target_sources(${PROJECT_NAME} FILES ${HEADERS} ) +target_link_libraries(${PROJECT_NAME} PRIVATE + cae-compile-options +) + target_include_directories(${PROJECT_NAME} PUBLIC $ @@ -36,8 +40,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE $ ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_EXTENSIONS OFF diff --git a/modules/Utils/include/Utils/Path.hpp b/modules/Utils/include/Utils/Path.hpp index 25fd4dc..461c4ff 100644 --- a/modules/Utils/include/Utils/Path.hpp +++ b/modules/Utils/include/Utils/Path.hpp @@ -123,6 +123,16 @@ namespace utl return normalize(executableDir() / relativePath); } + /// + /// @param relativePath Relative path to be resolved + /// @return Resolved path relative to the user cwd + /// @brief + /// + static fs::path resolveRelativeToCwd(const fs::path &relativePath) + { + return normalize(fs::current_path() / relativePath); + } + }; // class Path } // namespace utl diff --git a/plugins/Renderer/OpenGL/CMakeLists.txt b/plugins/Renderer/OpenGL/CMakeLists.txt index 07dad22..a395d0f 100644 --- a/plugins/Renderer/OpenGL/CMakeLists.txt +++ b/plugins/Renderer/OpenGL/CMakeLists.txt @@ -1,4 +1,4 @@ -project(cae-opengl +project(cae-renderer-opengl DESCRIPTION "CAE OpenGL Renderer Plugin" LANGUAGES CXX ) @@ -41,12 +41,13 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ${OPENGL_INCLUDE_DIR} + ${glm_SOURCE_DIR} ) if (UNIX AND NOT APPLE) target_include_directories(${PROJECT_NAME} PRIVATE ${EGL_INCLUDE_DIRS}) endif () -set(PLATFORM_LIBS cae-modules OpenGL::GL glad) +set(PLATFORM_LIBS cae-modules OpenGL::GL glad glm::glm) if (UNIX AND NOT APPLE) list(APPEND PLATFORM_LIBS ${EGL_LIBRARIES}) elseif (APPLE) @@ -54,8 +55,6 @@ elseif (APPLE) endif () target_link_libraries(${PROJECT_NAME} PRIVATE ${PLATFORM_LIBS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) set_target_properties(${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PLUGIN_DIR}" RUNTIME_OUTPUT_DIRECTORY "${PLUGIN_DIR}" diff --git a/plugins/Renderer/OpenGL/include/OPGL/Context/EGLContextLinux.hpp b/plugins/Renderer/OpenGL/include/OPGL/Context/EGLContext.hpp similarity index 73% rename from plugins/Renderer/OpenGL/include/OPGL/Context/EGLContextLinux.hpp rename to plugins/Renderer/OpenGL/include/OPGL/Context/EGLContext.hpp index 7f19a22..4450cf5 100644 --- a/plugins/Renderer/OpenGL/include/OPGL/Context/EGLContextLinux.hpp +++ b/plugins/Renderer/OpenGL/include/OPGL/Context/EGLContext.hpp @@ -1,6 +1,6 @@ /// -/// @file EGLContextLinux.hpp -/// @brief This file contains the EGLContextLinux class declaration +/// @file EGLContext.hpp +/// @brief This file contains the EGLContext_ class declaration /// @namespace cae /// @@ -16,15 +16,15 @@ namespace cae { /// - /// @class EGLContextLinux + /// @class EGLContext_ /// @brief Implementation of IContext for Linux using EGL /// @namespace cae /// - class EGLContextLinux final : public IContext + class EGLContext_ final : public IContext { public: - explicit EGLContextLinux() = default; - ~EGLContextLinux() override; + explicit EGLContext_() = default; + ~EGLContext_() override; void initialize(const NativeWindowHandle &window) override; @@ -42,7 +42,7 @@ namespace cae EGLSurface m_surface = EGL_NO_SURFACE; EGLContext m_context = EGL_NO_CONTEXT; - }; // class EGLContextLinux + }; // class EGLContext_ } // namespace cae diff --git a/plugins/Renderer/OpenGL/include/OPGL/Context/IContext.hpp b/plugins/Renderer/OpenGL/include/OPGL/Context/IContext.hpp index 467ed96..3f3fe30 100644 --- a/plugins/Renderer/OpenGL/include/OPGL/Context/IContext.hpp +++ b/plugins/Renderer/OpenGL/include/OPGL/Context/IContext.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/IWindow.hpp" +#include "Interfaces/Window/IWindow.hpp" #include @@ -22,14 +22,30 @@ namespace cae public: virtual ~IContext() = default; + /// + /// @param window The native window handle + /// @brief Initialize the OpenGL context with the given window + /// virtual void initialize(const NativeWindowHandle &window) = 0; + /// + /// @brief Swap the front and back buffers + /// virtual void swapBuffers() = 0; + /// + /// @param enabled Whether VSync should be enabled + /// @brief Enable or disable VSync + /// virtual void setVSyncEnabled(bool enabled) = 0; + + /// + /// @return Whether VSync is enabled + /// @brief Check if VSync is enabled + /// [[nodiscard]] virtual bool isVSyncEnabled() const = 0; - GladGLContext gl{0}; + GladGLContext gl{nullptr}; }; // interface IContext diff --git a/plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContextMac.hpp b/plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContext.hpp similarity index 66% rename from plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContextMac.hpp rename to plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContext.hpp index 675b825..ec4889d 100644 --- a/plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContextMac.hpp +++ b/plugins/Renderer/OpenGL/include/OPGL/Context/NSGLContext.hpp @@ -1,6 +1,6 @@ /// -/// @file NSGLContextMac.hpp -/// @brief This file contains the NSGLContextMac class declaration +/// @file NSGLContext.hpp +/// @brief This file contains the NSGLContext class declaration /// @namespace cae /// @@ -14,15 +14,15 @@ namespace cae { /// - /// @class NSGLContextMac + /// @class NSGLContext /// @brief Implementation of IContext for macOS using NSGL /// @namespace cae /// - class NSGLContextMac final : public IContext + class NSGLContext final : public IContext { public: - NSGLContextMac() = default; - ~NSGLContextMac() override; + NSGLContext() = default; + ~NSGLContext() override; void initialize(const NativeWindowHandle &window) override; @@ -34,7 +34,7 @@ namespace cae private: void *m_context = nullptr; - }; // class NSGLContextMac + }; // class NSGLContext } // namespace cae diff --git a/plugins/Renderer/OpenGL/include/OPGL/Context/WGLContextWindows.hpp b/plugins/Renderer/OpenGL/include/OPGL/Context/WGLContext.hpp similarity index 71% rename from plugins/Renderer/OpenGL/include/OPGL/Context/WGLContextWindows.hpp rename to plugins/Renderer/OpenGL/include/OPGL/Context/WGLContext.hpp index 845b985..532d671 100644 --- a/plugins/Renderer/OpenGL/include/OPGL/Context/WGLContextWindows.hpp +++ b/plugins/Renderer/OpenGL/include/OPGL/Context/WGLContext.hpp @@ -1,6 +1,6 @@ /// -/// @file WGLContextWindows.hpp -/// @brief This file contains the WGLContextWindows class declaration +/// @file WGLContext.hpp +/// @brief This file contains the WGLContext class declaration /// @namespace cae /// @@ -16,15 +16,15 @@ namespace cae { /// - /// @class WGLContextWindows + /// @class WGLContext /// @brief Implementation of IContext for Windows using WGL /// @namespace cae /// - class WGLContextWindows final : public IContext + class WGLContext final : public IContext { public: - WGLContextWindows() = default; - ~WGLContextWindows() override; + WGLContext() = default; + ~WGLContext() override; void initialize(const NativeWindowHandle &window) override; void swapBuffers() override; @@ -40,7 +40,7 @@ namespace cae HDC m_hdc = nullptr; HGLRC m_hglrc = nullptr; - }; // class WGLContextWindows + }; // class WGLContext } // namespace cae diff --git a/plugins/Renderer/OpenGL/include/OPGL/OPGL.hpp b/plugins/Renderer/OpenGL/include/OPGL/OPGL.hpp index dc7d9b7..cd881d0 100644 --- a/plugins/Renderer/OpenGL/include/OPGL/OPGL.hpp +++ b/plugins/Renderer/OpenGL/include/OPGL/OPGL.hpp @@ -56,7 +56,7 @@ namespace cae void initialize(const NativeWindowHandle &nativeWindowHandle, const Color &clearColor) override; void createPipeline(const ShaderID &id, const ShaderIRModule &vertex, const ShaderIRModule &fragment) override; - void draw(const WindowSize &windowSize, const ShaderID &shaderId) override; + void draw(const WindowSize &windowSize, const ShaderID &shaderId, glm::mat4 mvp) override; void createMesh(const std::vector &vertices) override; private: @@ -64,9 +64,8 @@ namespace cae std::unordered_map m_programs; Mesh m_mesh; - GladGLContext m_device{}; - - static GLuint createGLShader(GLenum type, const ShaderIRModule &data, GladGLContext gl); + GLuint m_ubo; + static GLuint createGLShader(GLenum type, const ShaderIRModule &data, const GladGLContext &gl); }; // class OPGL diff --git a/plugins/Renderer/OpenGL/src/context/EGLContextLinux.cpp b/plugins/Renderer/OpenGL/src/context/EGLContext.cpp similarity index 91% rename from plugins/Renderer/OpenGL/src/context/EGLContextLinux.cpp rename to plugins/Renderer/OpenGL/src/context/EGLContext.cpp index 4729f7a..f1ab024 100644 --- a/plugins/Renderer/OpenGL/src/context/EGLContextLinux.cpp +++ b/plugins/Renderer/OpenGL/src/context/EGLContext.cpp @@ -1,10 +1,10 @@ #ifdef __linux__ -#include "OPGL/Context/EGLContextLinux.hpp" +#include "OPGL/Context/EGLContext.hpp" #include -cae::EGLContextLinux::~EGLContextLinux() +cae::EGLContext_::~EGLContext_() { if (m_display != EGL_NO_DISPLAY) { @@ -21,7 +21,7 @@ cae::EGLContextLinux::~EGLContextLinux() } } -void cae::EGLContextLinux::initialize(const NativeWindowHandle &window) +void cae::EGLContext_::initialize(const NativeWindowHandle &window) { if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) { @@ -87,7 +87,7 @@ void cae::EGLContextLinux::initialize(const NativeWindowHandle &window) } } -void cae::EGLContextLinux::swapBuffers() +void cae::EGLContext_::swapBuffers() { if (m_display != EGL_NO_DISPLAY && m_surface != EGL_NO_SURFACE) { @@ -95,7 +95,7 @@ void cae::EGLContextLinux::swapBuffers() } } -void cae::EGLContextLinux::setVSyncEnabled(const bool enabled) +void cae::EGLContext_::setVSyncEnabled(const bool enabled) { if (m_display != EGL_NO_DISPLAY) { diff --git a/plugins/Renderer/OpenGL/src/context/NSGLContextMac.mm b/plugins/Renderer/OpenGL/src/context/NSGLContext.mm similarity index 76% rename from plugins/Renderer/OpenGL/src/context/NSGLContextMac.mm rename to plugins/Renderer/OpenGL/src/context/NSGLContext.mm index 5dd3b15..c1bf7d6 100644 --- a/plugins/Renderer/OpenGL/src/context/NSGLContextMac.mm +++ b/plugins/Renderer/OpenGL/src/context/NSGLContext.mm @@ -1,18 +1,18 @@ -#if defined(__APPLE__) +#ifdef __APPLE__ -#include "OPGL/Context/NSGLContextMac.hpp" +#include "OPGL/Context/NSGLContext.hpp" #import -cae::NSGLContextMac::~NSGLContextMac() { +cae::NSGLContext::~NSGLContext() { if (m_context) { [(NSOpenGLContext*)m_context clearDrawable]; m_context = nil; } } -void cae::NSGLContextMac::initialize(const NativeWindowHandle &window) { - NSView* nsview = (__bridge NSView*)window.window; +void cae::NSGLContext::initialize(const NativeWindowHandle &window) { + NSView* nsview = (__bridge NSView*)window.display; NSOpenGLPixelFormatAttribute attrs[] = { NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, @@ -35,19 +35,19 @@ } } -void cae::NSGLContextMac::swapBuffers() { +void cae::NSGLContext::swapBuffers() { if (m_context) [(NSOpenGLContext*)m_context flushBuffer]; } -void cae::NSGLContextMac::setVSyncEnabled(const bool enabled) { +void cae::NSGLContext::setVSyncEnabled(const bool enabled) { if (m_context) { GLint sync = enabled ? 1 : 0; [(NSOpenGLContext*)m_context setValues:&sync forParameter:NSOpenGLContextParameterSwapInterval]; } } -bool cae::NSGLContextMac::isVSyncEnabled() const { +bool cae::NSGLContext::isVSyncEnabled() const { if (m_context) { GLint sync = 0; [(NSOpenGLContext*)m_context getValues:&sync forParameter:NSOpenGLContextParameterSwapInterval]; @@ -56,4 +56,4 @@ return false; } -#endif // defined(__APPLE__) \ No newline at end of file +#endif \ No newline at end of file diff --git a/plugins/Renderer/OpenGL/src/context/WGLContextWindows.cpp b/plugins/Renderer/OpenGL/src/context/WGLContext.cpp similarity index 88% rename from plugins/Renderer/OpenGL/src/context/WGLContextWindows.cpp rename to plugins/Renderer/OpenGL/src/context/WGLContext.cpp index c3a8e5e..f5fa8d8 100644 --- a/plugins/Renderer/OpenGL/src/context/WGLContextWindows.cpp +++ b/plugins/Renderer/OpenGL/src/context/WGLContext.cpp @@ -1,11 +1,9 @@ #ifdef _WIN32 -#include "OPGL/Context/WGLContextWindows.hpp" +#include "OPGL/Context/WGLContext.hpp" #include "Utils/Logger.hpp" -#include - #include typedef HGLRC(WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); @@ -36,7 +34,8 @@ static void *win32GetGLProc(const char *name) { auto *proc = (void *)wglGetProcAddress(name); - if (proc == nullptr || proc == (void *)0x1 || proc == (void *)0x2 || proc == (void *)0x3 || proc == (void *)-1) + if (proc == nullptr || proc == reinterpret_cast(0x1) || proc == reinterpret_cast(0x2) || + proc == reinterpret_cast(0x3) || proc == reinterpret_cast(-1)) { if (g_opengl32 == nullptr) { @@ -49,7 +48,7 @@ static void *win32GetGLProc(const char *name) return proc; } -cae::WGLContextWindows::~WGLContextWindows() +cae::WGLContext::~WGLContext() { if (m_hglrc != nullptr) { @@ -62,12 +61,14 @@ cae::WGLContextWindows::~WGLContextWindows() } } -void cae::WGLContextWindows::initialize(const NativeWindowHandle &window) +void cae::WGLContext::initialize(const NativeWindowHandle &window) { m_hwnd = static_cast(window.window); m_hdc = GetDC(m_hwnd); if (m_hdc == nullptr) + { throw std::runtime_error("Failed to get HDC from HWND"); + } PIXELFORMATDESCRIPTOR pfd{}; pfd.nSize = sizeof(pfd); @@ -90,9 +91,13 @@ void cae::WGLContextWindows::initialize(const NativeWindowHandle &window) const HGLRC tempContext = wglCreateContext(m_hdc); if (tempContext == nullptr) + { throw std::runtime_error("Failed to create temporary WGL context"); + } if (wglMakeCurrent(m_hdc, tempContext) == 0) + { throw std::runtime_error("Failed to make temporary context current"); + } const auto wglCreateContextAttribsARB = reinterpret_cast(wglGetProcAddress("wglCreateContextAttribsARB")); @@ -134,21 +139,23 @@ void cae::WGLContextWindows::initialize(const NativeWindowHandle &window) { throw std::runtime_error("Current WGL context is not the one just created"); } - if (const int version = gladLoadGLContext(&gl, GLADloadfunc(win32GetGLProc)); version == 0) + if (const int version = gladLoadGLContext(&gl, reinterpret_cast(win32GetGLProc)); version == 0) { throw std::runtime_error("Failed to initialize GLAD MX (Windows)"); } if (gl.Enable != nullptr) { gl.Enable(GL_DEBUG_OUTPUT); +#ifdef CAE_DEBUG gl.DebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { utl::Logger::log("[GL DEBUG] " + std::string(message), utl::LogLevel::WARNING); }, nullptr); +#endif } } -void cae::WGLContextWindows::swapBuffers() +void cae::WGLContext::swapBuffers() { if (m_hdc != nullptr) { @@ -156,7 +163,7 @@ void cae::WGLContextWindows::swapBuffers() } } -void cae::WGLContextWindows::setVSyncEnabled(const bool enabled) +void cae::WGLContext::setVSyncEnabled(const bool enabled) { using PFNWGLSWAPINTERVALEXTPROC = BOOL(WINAPI *)(int); static auto wglSwapIntervalEXT = diff --git a/plugins/Renderer/OpenGL/src/opgl.cpp b/plugins/Renderer/OpenGL/src/opgl.cpp index a57fc02..99f9409 100644 --- a/plugins/Renderer/OpenGL/src/opgl.cpp +++ b/plugins/Renderer/OpenGL/src/opgl.cpp @@ -1,39 +1,51 @@ #include "OPGL/OPGL.hpp" #ifdef __linux__ -#include "OPGL/Context/EGLContextLinux.hpp" +#include "OPGL/Context/EGLContext.hpp" #elifdef _WIN32 -#include "OPGL/Context/WGLContextWindows.hpp" +#include "OPGL/Context/WGLContext.hpp" #elifdef __APPLE__ -#include "OPGL/Context/NSGLContextMac.hpp" +#include "OPGL/Context/NSGLContext.hpp" #endif +#include + #include void cae::OPGL::initialize(const NativeWindowHandle &nativeWindowHandle, const Color &clearColor) { #ifdef __linux__ - m_context = std::make_unique(); + m_context = std::make_unique(); #elifdef _WIN32 - m_context = std::make_unique(); + m_context = std::make_unique(); #elifdef __APPLE__ - m_context = std::make_unique(); + m_context = std::make_unique(); #endif m_context->initialize(nativeWindowHandle); - auto &gl = m_context->gl; + const auto &gl = m_context->gl; gl.Enable(GL_DEPTH_TEST); gl.ClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + + gl.GenBuffers(1, &m_ubo); + gl.BindBuffer(GL_UNIFORM_BUFFER, m_ubo); + gl.BufferData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), nullptr, GL_DYNAMIC_DRAW); + gl.BindBufferBase(GL_UNIFORM_BUFFER, 0, m_ubo); + gl.BindBuffer(GL_UNIFORM_BUFFER, 0); } -void cae::OPGL::draw(const WindowSize &windowSize, const ShaderID &shaderId) +void cae::OPGL::draw(const WindowSize &windowSize, const ShaderID &shaderId, const glm::mat4 mvp) { - auto &gl = m_context->gl; + const auto &gl = m_context->gl; gl.Viewport(0, 0, windowSize.width, windowSize.height); gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl.UseProgram(m_programs.at(shaderId)); + gl.BindBuffer(GL_UNIFORM_BUFFER, m_ubo); + gl.BufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), &mvp); + + // binding = 0 car dans le shader: layout(binding = 0) gl.BindVertexArray(m_mesh.vao); gl.DrawArrays(GL_TRIANGLES, 0, m_mesh.vertexCount); gl.BindVertexArray(0); @@ -43,11 +55,11 @@ void cae::OPGL::draw(const WindowSize &windowSize, const ShaderID &shaderId) void cae::OPGL::createPipeline(const ShaderID &id, const ShaderIRModule &vertex, const ShaderIRModule &fragment) { - auto &gl = m_context->gl; + const auto &gl = m_context->gl; const GLuint program = gl.CreateProgram(); - GLuint vs = createGLShader(GL_VERTEX_SHADER, vertex, gl); - GLuint fs = createGLShader(GL_FRAGMENT_SHADER, fragment, gl); + const GLuint vs = createGLShader(GL_VERTEX_SHADER, vertex, gl); + const GLuint fs = createGLShader(GL_FRAGMENT_SHADER, fragment, gl); gl.AttachShader(program, vs); gl.AttachShader(program, fs); @@ -70,7 +82,7 @@ void cae::OPGL::createPipeline(const ShaderID &id, const ShaderIRModule &vertex, void cae::OPGL::createMesh(const std::vector &vertices) { - auto &gl = m_context->gl; + const auto &gl = m_context->gl; Mesh mesh{}; mesh.vertexCount = static_cast(vertices.size() / 5); @@ -81,10 +93,10 @@ void cae::OPGL::createMesh(const std::vector &vertices) gl.BindBuffer(GL_ARRAY_BUFFER, mesh.vbo); gl.BufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW); - gl.VertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), static_cast(0)); + gl.VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), static_cast(0)); gl.EnableVertexAttribArray(0); - gl.VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(2 * sizeof(float))); + gl.VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), reinterpret_cast(3 * sizeof(float))); gl.EnableVertexAttribArray(1); gl.BindBuffer(GL_ARRAY_BUFFER, 0); @@ -93,7 +105,7 @@ void cae::OPGL::createMesh(const std::vector &vertices) m_mesh = mesh; } -GLuint cae::OPGL::createGLShader(const GLenum type, const ShaderIRModule &data, GladGLContext gl) +GLuint cae::OPGL::createGLShader(const GLenum type, const ShaderIRModule &data, const GladGLContext &gl) { const GLuint shader = gl.CreateShader(type); diff --git a/plugins/Renderer/Vulkan/CMakeLists.txt b/plugins/Renderer/Vulkan/CMakeLists.txt index 2cfd729..a863d67 100644 --- a/plugins/Renderer/Vulkan/CMakeLists.txt +++ b/plugins/Renderer/Vulkan/CMakeLists.txt @@ -1,16 +1,13 @@ -project(cae-vulkan +project(cae-renderer-vulkan DESCRIPTION "CAE Vulkan Renderer Plugin" LANGUAGES C CXX ) find_package(Vulkan QUIET CONFIG) if(NOT Vulkan_FOUND) - message(STATUS "Vulkan SDK not found.") - include(FetchContent) - set(VULKAN_VERSION "v1.4.329") - + set(VULKAN_HEADERS_ENABLE_TESTS OFF CACHE BOOL "" FORCE) FetchContent_Declare( VulkanHeaders GIT_REPOSITORY "https://github.com/KhronosGroup/Vulkan-Headers.git" @@ -43,8 +40,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ${Vulkan_INCLUDE_DIRS} ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ${Vulkan_LIBRARIES} diff --git a/plugins/Renderer/Vulkan/include/VULKN/VULKN.hpp b/plugins/Renderer/Vulkan/include/VULKN/VULKN.hpp index 40bd6a9..2c2c989 100644 --- a/plugins/Renderer/Vulkan/include/VULKN/VULKN.hpp +++ b/plugins/Renderer/Vulkan/include/VULKN/VULKN.hpp @@ -8,6 +8,8 @@ #include "Interfaces/Renderer/ARenderer.hpp" +#include + namespace cae { @@ -42,7 +44,7 @@ namespace cae const ShaderIRModule &fragment) override { } - void draw(const WindowSize &windowSize, const ShaderID &shaderId) override {} + void draw(const WindowSize &windowSize, const ShaderID &shaderId, glm::mat4 mvp) override {} void createMesh(const std::vector &vertices) override {} }; // class VULKN diff --git a/plugins/Shader/Frontend/GLSL/CMakeLists.txt b/plugins/Shader/Frontend/GLSL/CMakeLists.txt index a4cddf3..201c203 100644 --- a/plugins/Shader/Frontend/GLSL/CMakeLists.txt +++ b/plugins/Shader/Frontend/GLSL/CMakeLists.txt @@ -1,17 +1,18 @@ -project(cae-glsl +project(cae-shaders-frontend-glsl DESCRIPTION "CAE GLSL Shader Frontend Plugin" LANGUAGES C CXX ) find_package(glslang QUIET CONFIG) if (NOT glslang_FOUND) - message(STATUS "glslang not found.") - include(FetchContent) + set(BUILD_EXTERNAL OFF CACHE BOOL "" FORCE) set(ENABLE_HLSL OFF CACHE BOOL "" FORCE) set(ENABLE_OPT OFF CACHE BOOL "" FORCE) set(ENABLE_SPIRV ON CACHE BOOL "" FORCE) + set(ENABLE_GLSLANG_BINARIES ON CACHE BOOL "" FORCE) set(GLSLANG_TESTS OFF CACHE BOOL "" FORCE) + set(ENABLE_PCH ON CACHE BOOL "" FORCE) FetchContent_Declare( glslang GIT_REPOSITORY "https://github.com/KhronosGroup/glslang.git" @@ -29,8 +30,6 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules glslang::glslang diff --git a/plugins/Shader/Frontend/GLSL/include/GLSL/GLSL.hpp b/plugins/Shader/Frontend/GLSL/include/GLSL/GLSL.hpp index e9a7980..b49e6b8 100644 --- a/plugins/Shader/Frontend/GLSL/include/GLSL/GLSL.hpp +++ b/plugins/Shader/Frontend/GLSL/include/GLSL/GLSL.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/Shader/IShaderFrontend.hpp" +#include "Interfaces/Shader/Frontend/AShaderFrontend.hpp" #include @@ -22,7 +22,7 @@ namespace cae /// @brief Class for the GLSL plugin /// @namespace cae /// - class GLSL final : public IShaderFrontend + class GLSL final : public AShaderFrontend { public: diff --git a/plugins/Shader/Frontend/HLSL/CMakeLists.txt b/plugins/Shader/Frontend/HLSL/CMakeLists.txt index 69c24a2..2968a32 100644 --- a/plugins/Shader/Frontend/HLSL/CMakeLists.txt +++ b/plugins/Shader/Frontend/HLSL/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ) diff --git a/plugins/Shader/Frontend/MSL/CMakeLists.txt b/plugins/Shader/Frontend/MSL/CMakeLists.txt index b226d8a..084f52a 100644 --- a/plugins/Shader/Frontend/MSL/CMakeLists.txt +++ b/plugins/Shader/Frontend/MSL/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ) diff --git a/plugins/Shader/Frontend/WGSL/CMakeLists.txt b/plugins/Shader/Frontend/WGSL/CMakeLists.txt index 7c455b2..ac47e38 100644 --- a/plugins/Shader/Frontend/WGSL/CMakeLists.txt +++ b/plugins/Shader/Frontend/WGSL/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ) diff --git a/plugins/Shader/IR/DXC/CMakeLists.txt b/plugins/Shader/IR/DXC/CMakeLists.txt index 1a2f962..71f7eae 100644 --- a/plugins/Shader/IR/DXC/CMakeLists.txt +++ b/plugins/Shader/IR/DXC/CMakeLists.txt @@ -10,8 +10,6 @@ add_library(${PROJECT_NAME} SHARED ${SOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ) diff --git a/plugins/Shader/IR/SPIRV/CMakeLists.txt b/plugins/Shader/IR/SPIRV/CMakeLists.txt index 9c13c54..c4877b5 100644 --- a/plugins/Shader/IR/SPIRV/CMakeLists.txt +++ b/plugins/Shader/IR/SPIRV/CMakeLists.txt @@ -10,7 +10,7 @@ ## set(SPIRV_TOOLS_INCLUDE_DIR ${spirv-headers_SOURCE_DIR}) ## FetchContent_MakeAvailable(spirv-tools) -project(cae-spirv +project(cae-shaders-ir-spirv DESCRIPTION "CAE SPIRV Shader Intermediate Representation Plugin" LANGUAGES C CXX ) @@ -20,7 +20,7 @@ include(FetchContent) find_package(SPIRV-Headers QUIET CONFIG) if(NOT SPIRV-Headers_FOUND) - message(STATUS "SPIRV-Headers not found.") + set(SPIRV_HEADERS_ENABLE_TESTS OFF CACHE BOOL "" FORCE) FetchContent_Declare( spirv-headers GIT_REPOSITORY "https://github.com/KhronosGroup/SPIRV-Headers.git" @@ -38,7 +38,8 @@ endif() find_package(SPIRV-Cross QUIET CONFIG) if(NOT SPIRV-Cross_FOUND) - message(STATUS "SPIRV-Cross not found.") + set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + set(SPIRV_CROSS_CLI OFF CACHE BOOL "" FORCE) FetchContent_Declare( spirv-cross GIT_REPOSITORY "https://github.com/KhronosGroup/SPIRV-Cross.git" @@ -81,8 +82,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ${SPIRV_CROSS_LIBS} ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) set_target_properties(${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PLUGIN_DIR}" RUNTIME_OUTPUT_DIRECTORY "${PLUGIN_DIR}" diff --git a/plugins/Shader/IR/SPIRV/include/SPIRV/SPIRV.hpp b/plugins/Shader/IR/SPIRV/include/SPIRV/SPIRV.hpp index 12148a1..21e09b0 100644 --- a/plugins/Shader/IR/SPIRV/include/SPIRV/SPIRV.hpp +++ b/plugins/Shader/IR/SPIRV/include/SPIRV/SPIRV.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/Shader/IShaderIR.hpp" +#include "Interfaces/Shader/IR/AShaderIR.hpp" namespace cae { @@ -16,7 +16,7 @@ namespace cae /// @brief Class for the SPIR-V IR plugin /// @namespace cae /// - class SPIRV final : public IShaderIR + class SPIRV final : public AShaderIR { public: SPIRV() = default; diff --git a/plugins/Window/CMakeLists.txt b/plugins/Window/CMakeLists.txt index 033b108..0d7a915 100644 --- a/plugins/Window/CMakeLists.txt +++ b/plugins/Window/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(Cocoa) add_subdirectory(GLFW) add_subdirectory(Win32) add_subdirectory(X11) \ No newline at end of file diff --git a/plugins/Window/Cocoa/CMakeLists.txt b/plugins/Window/Cocoa/CMakeLists.txt index e69de29..edbdaf0 100644 --- a/plugins/Window/Cocoa/CMakeLists.txt +++ b/plugins/Window/Cocoa/CMakeLists.txt @@ -0,0 +1,27 @@ +project(cae-window-cocoa + DESCRIPTION "CAE Cocoa Window Plugin" + LANGUAGES C CXX +) + +if (NOT APPLE) + message(WARNING "${PROJECT_NAME} can only be build on MacOS") + return() +else () + enable_language(OBJCXX) +endif () + +file(GLOB_RECURSE SOURCES "${PROJECT_SOURCE_DIR}/src/*.mm" "${PROJECT_SOURCE_DIR}/src/*.cpp") + +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +target_include_directories(${PROJECT_NAME} PRIVATE + "${PROJECT_SOURCE_DIR}/include" +) +target_link_libraries(${PROJECT_NAME} PRIVATE + cae-modules + "-framework Cocoa" +) +set_target_properties(${PROJECT_NAME} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PLUGIN_DIR}" + RUNTIME_OUTPUT_DIRECTORY "${PLUGIN_DIR}" +) diff --git a/plugins/Window/Cocoa/include/Cocoa/Cocoa.hpp b/plugins/Window/Cocoa/include/Cocoa/Cocoa.hpp index e69de29..ae9f8d7 100644 --- a/plugins/Window/Cocoa/include/Cocoa/Cocoa.hpp +++ b/plugins/Window/Cocoa/include/Cocoa/Cocoa.hpp @@ -0,0 +1,66 @@ +/// +/// @file Cocoa.hpp +/// @brief This file contains the hpp class declaration +/// @namespace cae +/// + +#pragma once + +#ifdef __APPLE__ + +#include "Interfaces/Window/AWindow.hpp" + +#include + +namespace cae +{ + + /// + /// @class Cocoa + /// @brief Class for the Cocoa plugin + /// @namespace cae + /// + class Cocoa final : public AWindow + { + public: + Cocoa() = default; + ~Cocoa() override; + + Cocoa(const Cocoa &) = delete; + Cocoa &operator=(const Cocoa &) = delete; + + [[nodiscard]] std::string getName() const override { return "Cocoa"; } + [[nodiscard]] utl::PluginType getType() const override { return utl::PluginType::WINDOW; } + [[nodiscard]] utl::PluginPlatform getPlatform() const override { return utl::PluginPlatform::MACOSX; } + + bool create(const std::string &name, WindowSize size) override; + void close() override; + + [[nodiscard]] NativeWindowHandle getNativeHandle() const override; + [[nodiscard]] WindowSize getWindowSize() const override; + + void setIcon(const std::string &path) const override {} + + [[nodiscard]] bool shouldClose() const override; + void pollEvents() override; + bool pollEvent(WindowEvent &event) override; + + [[nodiscard]] bool wasResized() const override { return m_resized; } + void resetResizedFlag() override { m_resized = false; } + + private: + void *m_window = nullptr; // NSWindow* + void *m_view = nullptr; // NSView* + void *m_app = nullptr; // NSApplication* + + bool m_shouldClose = false; + bool m_resized = false; + + std::queue m_eventQueue; + WindowSize m_size{}; + + }; // class Cocoa + +} // namespace cae + +#endif diff --git a/plugins/Window/Cocoa/src/cocoa.mm b/plugins/Window/Cocoa/src/cocoa.mm new file mode 100644 index 0000000..add1157 --- /dev/null +++ b/plugins/Window/Cocoa/src/cocoa.mm @@ -0,0 +1,136 @@ +#import + +#include "Cocoa/Cocoa.hpp" + +#include + +using namespace cae; + +Cocoa::~Cocoa() +{ + close(); +} + +bool Cocoa::create(const std::string& title, WindowSize size) +{ + @autoreleasepool + { + m_app = [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + NSRect rect = NSMakeRect(0, 0, size.width, size.height); + NSUInteger style = + NSWindowStyleMaskTitled | + NSWindowStyleMaskClosable | + NSWindowStyleMaskResizable; + + NSWindow* window = [[NSWindow alloc] + initWithContentRect:rect + styleMask:style + backing:NSBackingStoreBuffered + defer:NO]; + + [window setTitle:[NSString stringWithUTF8String:title.c_str()]]; + [window makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; + + m_window = window; + m_view = [window contentView]; + m_size = size; + } + + return true; +} + +void Cocoa::close() +{ + if (m_window) + { + NSWindow* window = (NSWindow*)m_window; + [window close]; + m_window = nullptr; + m_view = nullptr; + } +} + +void Cocoa::pollEvents() +{ + @autoreleasepool + { + NSEvent* event; + while ((event = [NSApp + nextEventMatchingMask:NSEventMaskAny + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES])) + { + switch ([event type]) + { + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: + { + WindowEvent e{}; + e.type = ([event type] == NSEventTypeKeyDown) + ? WindowEventType::KeyDown + : WindowEventType::KeyUp; + // mapping clavier à faire ici + m_eventQueue.push(e); + break; + } + + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseUp: + { + WindowEvent e{}; + e.type = ([event type] == NSEventTypeLeftMouseDown) + ? WindowEventType::MouseButtonDown + : WindowEventType::MouseButtonUp; + e.mouseButton.button = MouseButton::Left; + m_eventQueue.push(e); + break; + } + + default: + break; + } + + [NSApp sendEvent:event]; + } + } +} + +bool Cocoa::pollEvent(WindowEvent& event) +{ + if (m_eventQueue.empty()) + return false; + + event = m_eventQueue.front(); + m_eventQueue.pop(); + return true; +} + +bool Cocoa::shouldClose() const +{ + return m_shouldClose; +} + +WindowSize Cocoa::getWindowSize() const +{ + if (!m_window) + return {}; + + NSWindow* window = (NSWindow*)m_window; + NSRect rect = [window frame]; + return { + .width = (uint16_t)rect.size.width, + .height = (uint16_t)rect.size.height + }; +} + +NativeWindowHandle Cocoa::getNativeHandle() const +{ + NativeWindowHandle handle{}; + handle.window = m_window; // NSWindow* + handle.display = m_view; // NSView* + return handle; +} diff --git a/plugins/Window/Cocoa/src/entrypoint.cpp b/plugins/Window/Cocoa/src/entrypoint.cpp index e69de29..fdd9e7c 100644 --- a/plugins/Window/Cocoa/src/entrypoint.cpp +++ b/plugins/Window/Cocoa/src/entrypoint.cpp @@ -0,0 +1,8 @@ +#include "Cocoa/Cocoa.hpp" + +#include + +extern "C" +{ + PLUGIN_EXPORT cae::IWindow *entryPoint() { return std::make_unique().release(); } +} diff --git a/plugins/Window/GLFW/CMakeLists.txt b/plugins/Window/GLFW/CMakeLists.txt index 48cae68..eb241ce 100644 --- a/plugins/Window/GLFW/CMakeLists.txt +++ b/plugins/Window/GLFW/CMakeLists.txt @@ -1,4 +1,4 @@ -project(cae-glfw +project(cae-window-glfw DESCRIPTION "CAE GLFW Window Plugin" LANGUAGES C CXX ) @@ -44,8 +44,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ${GLFW_INCLUDE_DIR} ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ${GLFW_LIB} diff --git a/plugins/Window/GLFW/include/GLFW/GLFW.hpp b/plugins/Window/GLFW/include/GLFW/GLFW.hpp index 8d8acd6..6160815 100644 --- a/plugins/Window/GLFW/include/GLFW/GLFW.hpp +++ b/plugins/Window/GLFW/include/GLFW/GLFW.hpp @@ -6,7 +6,7 @@ #pragma once -#include "Interfaces/IWindow.hpp" +#include "Interfaces/Window/AWindow.hpp" #ifdef _WIN32 #define GLFW_EXPOSE_NATIVE_WIN32 @@ -17,6 +17,8 @@ #endif #include +#include + namespace cae { @@ -25,7 +27,7 @@ namespace cae /// @brief Class for the GLFW plugin /// @namespace cae /// - class GLFW final : public IWindow + class GLFW final : public AWindow { public: @@ -47,16 +49,23 @@ namespace cae [[nodiscard]] NativeWindowHandle getNativeHandle() const override; [[nodiscard]] WindowSize getWindowSize() const override; - [[nodiscard]] bool setIcon(const std::string &path) const override; + void setIcon(const std::string &path) const override; [[nodiscard]] bool shouldClose() const override { return glfwWindowShouldClose(m_window) != 0; } void pollEvents() override { glfwPollEvents(); } + bool pollEvent(WindowEvent &event) override; [[nodiscard]] bool wasResized() const override { return m_frameBufferResized; } void resetResizedFlag() override { m_frameBufferResized = false; } private: static void frameBufferResizeCallback(GLFWwindow *window, int width, int height); + static void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); + static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods); + static void cursorPosCallback(GLFWwindow *window, double x, double y); + static void scrollCallback(GLFWwindow *window, double xoffset, double yoffset); + + std::queue m_eventQueue; GLFWwindow *m_window = nullptr; WindowSize m_frameBufferSize{}; diff --git a/plugins/Window/GLFW/src/glfw.cpp b/plugins/Window/GLFW/src/glfw.cpp index ba33822..fbf8052 100644 --- a/plugins/Window/GLFW/src/glfw.cpp +++ b/plugins/Window/GLFW/src/glfw.cpp @@ -5,11 +5,264 @@ #include +#include + +static cae::KeyCode translateKey(const int key) +{ + switch (key) + { + case GLFW_KEY_A: + return cae::KeyCode::A; + case GLFW_KEY_B: + return cae::KeyCode::B; + case GLFW_KEY_C: + return cae::KeyCode::C; + case GLFW_KEY_D: + return cae::KeyCode::D; + case GLFW_KEY_E: + return cae::KeyCode::E; + case GLFW_KEY_F: + return cae::KeyCode::F; + case GLFW_KEY_G: + return cae::KeyCode::G; + case GLFW_KEY_H: + return cae::KeyCode::H; + case GLFW_KEY_I: + return cae::KeyCode::I; + case GLFW_KEY_J: + return cae::KeyCode::J; + case GLFW_KEY_K: + return cae::KeyCode::K; + case GLFW_KEY_L: + return cae::KeyCode::L; + case GLFW_KEY_M: + return cae::KeyCode::M; + case GLFW_KEY_N: + return cae::KeyCode::N; + case GLFW_KEY_O: + return cae::KeyCode::O; + case GLFW_KEY_P: + return cae::KeyCode::P; + case GLFW_KEY_Q: + return cae::KeyCode::Q; + case GLFW_KEY_R: + return cae::KeyCode::R; + case GLFW_KEY_S: + return cae::KeyCode::S; + case GLFW_KEY_T: + return cae::KeyCode::T; + case GLFW_KEY_U: + return cae::KeyCode::U; + case GLFW_KEY_V: + return cae::KeyCode::V; + case GLFW_KEY_W: + return cae::KeyCode::W; + case GLFW_KEY_X: + return cae::KeyCode::X; + case GLFW_KEY_Y: + return cae::KeyCode::Y; + case GLFW_KEY_Z: + return cae::KeyCode::Z; + + case GLFW_KEY_0: + return cae::KeyCode::Num0; + case GLFW_KEY_1: + return cae::KeyCode::Num1; + case GLFW_KEY_2: + return cae::KeyCode::Num2; + case GLFW_KEY_3: + return cae::KeyCode::Num3; + case GLFW_KEY_4: + return cae::KeyCode::Num4; + case GLFW_KEY_5: + return cae::KeyCode::Num5; + case GLFW_KEY_6: + return cae::KeyCode::Num6; + case GLFW_KEY_7: + return cae::KeyCode::Num7; + case GLFW_KEY_8: + return cae::KeyCode::Num8; + case GLFW_KEY_9: + return cae::KeyCode::Num9; + + case GLFW_KEY_LEFT_SHIFT: + return cae::KeyCode::LShift; + case GLFW_KEY_RIGHT_SHIFT: + return cae::KeyCode::RShift; + case GLFW_KEY_LEFT_CONTROL: + return cae::KeyCode::LCtrl; + case GLFW_KEY_RIGHT_CONTROL: + return cae::KeyCode::RCtrl; + case GLFW_KEY_LEFT_ALT: + return cae::KeyCode::LAlt; + case GLFW_KEY_RIGHT_ALT: + return cae::KeyCode::RAlt; + case GLFW_KEY_LEFT_SUPER: + return cae::KeyCode::LSuper; + case GLFW_KEY_RIGHT_SUPER: + return cae::KeyCode::RSuper; + case GLFW_KEY_CAPS_LOCK: + return cae::KeyCode::CapsLock; + + case GLFW_KEY_UP: + return cae::KeyCode::Up; + case GLFW_KEY_DOWN: + return cae::KeyCode::Down; + case GLFW_KEY_LEFT: + return cae::KeyCode::Left; + case GLFW_KEY_RIGHT: + return cae::KeyCode::Right; + case GLFW_KEY_HOME: + return cae::KeyCode::Home; + case GLFW_KEY_END: + return cae::KeyCode::End; + case GLFW_KEY_PAGE_UP: + return cae::KeyCode::PageUp; + case GLFW_KEY_PAGE_DOWN: + return cae::KeyCode::PageDown; + + case GLFW_KEY_ENTER: + return cae::KeyCode::Enter; + case GLFW_KEY_BACKSPACE: + return cae::KeyCode::Backspace; + case GLFW_KEY_TAB: + return cae::KeyCode::Tab; + case GLFW_KEY_SPACE: + return cae::KeyCode::Space; + case GLFW_KEY_DELETE: + return cae::KeyCode::Delete; + case GLFW_KEY_INSERT: + return cae::KeyCode::Insert; + + case GLFW_KEY_F1: + return cae::KeyCode::F1; + case GLFW_KEY_F2: + return cae::KeyCode::F2; + case GLFW_KEY_F3: + return cae::KeyCode::F3; + case GLFW_KEY_F4: + return cae::KeyCode::F4; + case GLFW_KEY_F5: + return cae::KeyCode::F5; + case GLFW_KEY_F6: + return cae::KeyCode::F6; + case GLFW_KEY_F7: + return cae::KeyCode::F7; + case GLFW_KEY_F8: + return cae::KeyCode::F8; + case GLFW_KEY_F9: + return cae::KeyCode::F9; + case GLFW_KEY_F10: + return cae::KeyCode::F10; + case GLFW_KEY_F11: + return cae::KeyCode::F11; + case GLFW_KEY_F12: + return cae::KeyCode::F12; + + case GLFW_KEY_ESCAPE: + return cae::KeyCode::Escape; + case GLFW_KEY_PRINT_SCREEN: + return cae::KeyCode::PrintScreen; + case GLFW_KEY_PAUSE: + return cae::KeyCode::Pause; + case GLFW_KEY_MENU: + return cae::KeyCode::Menu; + + default: + return cae::KeyCode::Count; + } +} + +void cae::GLFW::keyCallback(GLFWwindow *window, const int key, int, const int action, int) +{ + auto *self = static_cast(glfwGetWindowUserPointer(window)); + if (self == nullptr) + { + return; + } + + WindowEvent e{}; + if (action == GLFW_PRESS) + { + e.type = WindowEventType::KeyDown; + } + else if (action == GLFW_RELEASE) + { + e.type = WindowEventType::KeyUp; + } + else + { + return; + } + + e.key.key = translateKey(key); + self->m_eventQueue.push(e); +} + +void cae::GLFW::mouseButtonCallback(GLFWwindow *window, int button, const int action, int) +{ + auto *self = static_cast(glfwGetWindowUserPointer(window)); + if (self == nullptr) + { + return; + } + + WindowEvent e{}; + e.type = (action == GLFW_PRESS) ? WindowEventType::MouseButtonDown : WindowEventType::MouseButtonUp; + + e.mouseButton.button = static_cast(button); + self->m_eventQueue.push(e); +} + +void cae::GLFW::cursorPosCallback(GLFWwindow *window, const double x, const double y) +{ + auto *self = static_cast(glfwGetWindowUserPointer(window)); + if (self == nullptr) + { + return; + } + + WindowEvent e{}; + e.type = WindowEventType::MouseMove; + e.mouseMove.x = static_cast(x); + e.mouseMove.y = static_cast(y); + + self->m_eventQueue.push(e); +} + +void cae::GLFW::scrollCallback(GLFWwindow *window, const double xoffset, const double yoffset) +{ + auto *self = static_cast(glfwGetWindowUserPointer(window)); + if (self == nullptr) + { + return; + } + + WindowEvent e{}; + e.type = WindowEventType::MouseScroll; + e.scroll.x = static_cast(xoffset); + e.scroll.y = static_cast(yoffset); + + self->m_eventQueue.push(e); +} + void cae::GLFW::frameBufferResizeCallback(GLFWwindow *window, const int width, const int height) { - auto *const self = static_cast(glfwGetWindowUserPointer(window)); + auto *self = static_cast(glfwGetWindowUserPointer(window)); + if (self == nullptr) + { + return; + } + self->m_frameBufferResized = true; self->m_frameBufferSize = {.width = static_cast(width), .height = static_cast(height)}; + + WindowEvent e{}; + e.type = WindowEventType::Resize; + e.resize.w = self->m_frameBufferSize.width; + e.resize.h = self->m_frameBufferSize.height; + + self->m_eventQueue.push(e); } bool cae::GLFW::create(const std::string &name, const WindowSize size) @@ -20,8 +273,11 @@ bool cae::GLFW::create(const std::string &name, const WindowSize size) utl::Logger::log("Failed to init glfw", utl::LogLevel::WARNING); return false; } - +#ifdef __APPLE__ +#else glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +#endif + m_window = glfwCreateWindow(size.width, size.height, name.c_str(), nullptr, nullptr); if (m_window == nullptr) { @@ -31,7 +287,15 @@ bool cae::GLFW::create(const std::string &name, const WindowSize size) return false; } glfwSetWindowUserPointer(m_window, this); + glfwSetFramebufferSizeCallback(m_window, frameBufferResizeCallback); + glfwSetKeyCallback(m_window, keyCallback); + glfwSetMouseButtonCallback(m_window, mouseButtonCallback); + glfwSetCursorPosCallback(m_window, cursorPosCallback); + glfwSetScrollCallback(m_window, scrollCallback); +#ifdef __APPLE__ + glfwMakeContextCurrent((GLFWwindow *)m_window); +#endif return true; } @@ -69,14 +333,26 @@ cae::NativeWindowHandle cae::GLFW::getNativeHandle() const return handle; } -bool cae::GLFW::setIcon(const std::string &path) const +void cae::GLFW::setIcon(const std::string &path) const { static const utl::Image image(path); if (image.pixels == nullptr) { - return false; + utl::Logger::log("Failed to create icon.", utl::LogLevel::WARNING); + return; } static const GLFWimage appIcon{.width = image.width, .height = image.height, .pixels = image.pixels}; glfwSetWindowIcon(m_window, 1, &appIcon); +} + +bool cae::GLFW::pollEvent(WindowEvent &event) +{ + if (m_eventQueue.empty()) + { + return false; + } + + event = m_eventQueue.front(); + m_eventQueue.pop(); return true; } diff --git a/plugins/Window/Win32/CMakeLists.txt b/plugins/Window/Win32/CMakeLists.txt index d34d0a0..77a22d2 100644 --- a/plugins/Window/Win32/CMakeLists.txt +++ b/plugins/Window/Win32/CMakeLists.txt @@ -4,7 +4,7 @@ project(cae-window-win32 ) if (NOT WIN32) - message(WARNING "${PROJECT_NAME} can only be build on windows") + message(WARNING "${PROJECT_NAME} can only be build on Windows") return() endif () @@ -22,16 +22,10 @@ endif() file(GLOB_RECURSE SOURCE "${PROJECT_SOURCE_DIR}/src/*.cpp") -file(GLOB_RECURSE HEADERS "${PROJECT_SOURCE_DIR}/include/*.hpp") -add_library(${PROJECT_NAME} SHARED - ${SOURCE} - ${HEADERS} -) +add_library(${PROJECT_NAME} SHARED ${SOURCE}) target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include") -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ${USER32_LIB} diff --git a/plugins/Window/Win32/include/Win32/Win32.hpp b/plugins/Window/Win32/include/Win32/Win32.hpp index 97c340d..b91ef53 100644 --- a/plugins/Window/Win32/include/Win32/Win32.hpp +++ b/plugins/Window/Win32/include/Win32/Win32.hpp @@ -6,10 +6,14 @@ #pragma once -#include "Interfaces/IWindow.hpp" +#ifdef _WIN32 + +#include "Interfaces/Window/AWindow.hpp" #include +#include + namespace cae { @@ -18,7 +22,7 @@ namespace cae /// @brief Class for the Win32 plugin /// @namespace cae /// - class Win32 final : public IWindow + class Win32 final : public AWindow { public: @@ -40,16 +44,19 @@ namespace cae [[nodiscard]] NativeWindowHandle getNativeHandle() const override; [[nodiscard]] WindowSize getWindowSize() const override; - [[nodiscard]] bool setIcon(const std::string &path) const override; + void setIcon(const std::string &path) const override; [[nodiscard]] bool shouldClose() const override { return m_shouldClose; } void pollEvents() override; + bool pollEvent(WindowEvent &event) override; bool wasResized() const override { return m_frameBufferResized; } void resetResizedFlag() override { m_frameBufferResized = false; } private: static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static KeyCode mapWinKey(WPARAM key); + std::queue m_eventQueue; std::wstring m_title; HWND m_hwnd = nullptr; @@ -59,4 +66,7 @@ namespace cae bool m_shouldClose = false; }; // class Win32 -} // namespace cae \ No newline at end of file + +} // namespace cae + +#endif diff --git a/plugins/Window/Win32/src/win32.cpp b/plugins/Window/Win32/src/win32.cpp index 4067c09..304195c 100644 --- a/plugins/Window/Win32/src/win32.cpp +++ b/plugins/Window/Win32/src/win32.cpp @@ -3,40 +3,130 @@ #include "Utils/Image.hpp" #include "Utils/Logger.hpp" +#include + #include +#include +#include constexpr wchar_t WINDOW_CLASS_NAME[] = L"CAE_WindowsWindowClass"; +cae::KeyCode cae::Win32::mapWinKey(const WPARAM key) +{ + static const std::unordered_map keyMap = { + {'A', KeyCode::A}, + {'B', KeyCode::B}, + {'C', KeyCode::C}, + {'D', KeyCode::D}, + {'E', KeyCode::E}, + {'F', KeyCode::F}, + {'G', KeyCode::G}, + {'H', KeyCode::H}, + {'I', KeyCode::I}, + {'J', KeyCode::J}, + {'K', KeyCode::K}, + {'L', KeyCode::L}, + {'M', KeyCode::M}, + {'N', KeyCode::N}, + {'O', KeyCode::O}, + {'P', KeyCode::P}, + {'Q', KeyCode::Q}, + {'R', KeyCode::R}, + {'S', KeyCode::S}, + {'T', KeyCode::T}, + {'U', KeyCode::U}, + {'V', KeyCode::V}, + {'W', KeyCode::W}, + {'X', KeyCode::X}, + {'Y', KeyCode::Y}, + {'Z', KeyCode::Z}, + + {'0', KeyCode::Num0}, + {'1', KeyCode::Num1}, + {'2', KeyCode::Num2}, + {'3', KeyCode::Num3}, + {'4', KeyCode::Num4}, + {'5', KeyCode::Num5}, + {'6', KeyCode::Num6}, + {'7', KeyCode::Num7}, + {'8', KeyCode::Num8}, + {'9', KeyCode::Num9}, + + {VK_ESCAPE, KeyCode::Escape}, + {VK_LEFT, KeyCode::Left}, + {VK_RIGHT, KeyCode::Right}, + {VK_UP, KeyCode::Up}, + {VK_DOWN, KeyCode::Down}, + {VK_SPACE, KeyCode::Space}, + {VK_RETURN, KeyCode::Enter}, + {VK_BACK, KeyCode::Backspace}, + {VK_TAB, KeyCode::Tab}, + {VK_LSHIFT, KeyCode::LShift}, + {VK_RSHIFT, KeyCode::RShift}, + {VK_LCONTROL, KeyCode::LCtrl}, + {VK_RCONTROL, KeyCode::RCtrl}, + {VK_LMENU, KeyCode::LAlt}, + {VK_RMENU, KeyCode::RAlt} + // ... + }; + + const auto it = keyMap.find(key); + return it != keyMap.end() ? it->second : KeyCode::Count; +} + LRESULT CALLBACK cae::Win32::WindowProc(const HWND hwnd, const UINT msg, const WPARAM wParam, const LPARAM lParam) { Win32 *self = nullptr; if (msg == WM_NCCREATE) { - auto *cs = reinterpret_cast(lParam); + const auto *cs = reinterpret_cast(lParam); self = static_cast(cs->lpCreateParams); SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast(self)); return TRUE; } self = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); + if (self == nullptr) + { + return DefWindowProcW(hwnd, msg, wParam, lParam); + } + WindowEvent e{}; switch (msg) { case WM_SIZE: - if (self != nullptr) - { - self->m_frameBufferResized = true; - self->m_frameBufferSize = {.width = LOWORD(lParam), .height = HIWORD(lParam)}; - } + self->m_frameBufferResized = true; + self->m_frameBufferSize = {.width = LOWORD(lParam), .height = HIWORD(lParam)}; + e.type = WindowEventType::Resize; + e.resize = {.w = LOWORD(lParam), .h = HIWORD(lParam)}; + self->m_eventQueue.push(e); return 0; case WM_DESTROY: PostQuitMessage(0); + e.type = WindowEventType::Close; + self->m_eventQueue.push(e); + return 0; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + e.type = WindowEventType::KeyDown; + e.key.key = mapWinKey(wParam); + self->m_eventQueue.push(e); return 0; - default: - return DefWindowProcW(hwnd, msg, wParam, lParam); + + case WM_KEYUP: + case WM_SYSKEYUP: + e.type = WindowEventType::KeyUp; + e.key.key = mapWinKey(wParam); + self->m_eventQueue.push(e); + return 0; + + // mouse, scroll, ... } + + return DefWindowProcW(hwnd, msg, wParam, lParam); } bool cae::Win32::create(const std::string &name, const WindowSize size) @@ -75,8 +165,8 @@ bool cae::Win32::create(const std::string &name, const WindowSize size) } classRegistered = true; } - m_hwnd = CreateWindowExW(0, WINDOW_CLASS_NAME, L"TEST TITLE VISIBLE", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, - CW_USEDEFAULT, size.width, size.height, nullptr, nullptr, m_hInstance, this); + m_hwnd = CreateWindowExW(0, WINDOW_CLASS_NAME, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, size.width, + size.height, nullptr, nullptr, m_hInstance, this); if (m_hwnd == nullptr) { @@ -110,13 +200,13 @@ cae::WindowSize cae::Win32::getWindowSize() const .height = static_cast(rect.bottom - rect.top)}; } -bool cae::Win32::setIcon(const std::string &path) const +void cae::Win32::setIcon(const std::string &path) const { try { const utl::Image image(path); - for (size_t i = 0; i < static_cast(image.width * image.height); ++i) + for (size_t i = 0; std::cmp_less(i, image.width * image.height); ++i) { std::swap(image.pixels[(i * 4) + 0], image.pixels[(i * 4) + 2]); } @@ -144,7 +234,8 @@ bool cae::Win32::setIcon(const std::string &path) const if (hBitmap == nullptr) { - return false; + utl::Logger::log("Failed to create window icon.", utl::LogLevel::WARNING); + return; } std::memcpy(pBits, image.pixels, static_cast(image.width * image.height * 4)); @@ -159,18 +250,16 @@ bool cae::Win32::setIcon(const std::string &path) const if (hIcon == nullptr) { - return false; + utl::Logger::log("Failed to create window icon", utl::LogLevel::WARNING); + return; } SendMessageW(m_hwnd, WM_SETICON, ICON_BIG, reinterpret_cast(hIcon)); SendMessageW(m_hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast(hIcon)); - - return true; } catch (const std::exception &e) { utl::Logger::log("Failed to load icon: " + std::string(e.what()), utl::LogLevel::WARNING); - return false; } } @@ -187,3 +276,22 @@ void cae::Win32::pollEvents() DispatchMessage(&msg); } } + +bool cae::Win32::pollEvent(WindowEvent &event) +{ + MSG msg{}; + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (!m_eventQueue.empty()) + { + event = m_eventQueue.front(); + m_eventQueue.pop(); + return true; + } + + return false; +} diff --git a/plugins/Window/X11/CMakeLists.txt b/plugins/Window/X11/CMakeLists.txt index b2df99c..008bcd9 100644 --- a/plugins/Window/X11/CMakeLists.txt +++ b/plugins/Window/X11/CMakeLists.txt @@ -1,8 +1,13 @@ -project(cae-x11 +project(cae-window-x11 DESCRIPTION "CAE X11 Window Plugin" LANGUAGES C CXX ) +if (NOT LINUX) + message(WARNING "${PROJECT_NAME} can only be build on Linux") + return() +endif () + find_package(X11) if (NOT X11_FOUND) message(WARNING "X11 not found, skipping ${PROJECT_NAME} build") @@ -17,8 +22,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include" ${X11_INCLUDE_DIR} ) -target_compile_options(${PROJECT_NAME} PRIVATE ${WARNING_FLAGS}) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) target_link_libraries(${PROJECT_NAME} PRIVATE cae-modules ${X11_LIBRARIES} diff --git a/plugins/Window/X11/include/X11/X11.hpp b/plugins/Window/X11/include/X11/X11.hpp index fcc4033..b23ccf5 100644 --- a/plugins/Window/X11/include/X11/X11.hpp +++ b/plugins/Window/X11/include/X11/X11.hpp @@ -6,10 +6,14 @@ #pragma once -#include "Interfaces/IWindow.hpp" +#ifdef __linux__ + +#include "Interfaces/Window/AWindow.hpp" #include +#include + namespace cae { @@ -18,7 +22,7 @@ namespace cae /// @brief Class for the X11 plugin /// @namespace cae /// - class X11 final : public IWindow + class X11 final : public AWindow { public: @@ -43,23 +47,26 @@ namespace cae } [[nodiscard]] WindowSize getWindowSize() const override; - [[nodiscard]] bool setIcon(const std::string &path) const override; + void setIcon(const std::string &path) const override; [[nodiscard]] bool shouldClose() const override; void pollEvents() override; + bool pollEvent(WindowEvent &outEvent) override; bool wasResized() const override { return m_frameBufferResized; } void resetResizedFlag() override { m_frameBufferResized = false; } private: - WindowSize m_frameBufferSize; - mutable bool m_frameBufferResized = false; - + std::queue m_eventQueue; Display *m_display = nullptr; Window m_window = 0; + WindowSize m_frameBufferSize; + mutable bool m_frameBufferResized = false; Atom m_wmDeleteMessage = 0; bool m_shouldClose = false; }; // class X11 } // namespace cae + +#endif diff --git a/plugins/Window/X11/src/x11.cpp b/plugins/Window/X11/src/x11.cpp index df7b946..f4561df 100644 --- a/plugins/Window/X11/src/x11.cpp +++ b/plugins/Window/X11/src/x11.cpp @@ -3,9 +3,184 @@ #include "Utils/Image.hpp" #include "Utils/Logger.hpp" +#include + +#include #include #include +static cae::KeyCode translateKeysym(const KeySym sym) +{ + switch (sym) + { + case XK_a: + return cae::KeyCode::A; + case XK_b: + return cae::KeyCode::B; + case XK_c: + return cae::KeyCode::C; + case XK_d: + return cae::KeyCode::D; + case XK_e: + return cae::KeyCode::E; + case XK_f: + return cae::KeyCode::F; + case XK_g: + return cae::KeyCode::G; + case XK_h: + return cae::KeyCode::H; + case XK_i: + return cae::KeyCode::I; + case XK_j: + return cae::KeyCode::J; + case XK_k: + return cae::KeyCode::K; + case XK_l: + return cae::KeyCode::L; + case XK_m: + return cae::KeyCode::M; + case XK_n: + return cae::KeyCode::N; + case XK_o: + return cae::KeyCode::O; + case XK_p: + return cae::KeyCode::P; + case XK_q: + return cae::KeyCode::Q; + case XK_r: + return cae::KeyCode::R; + case XK_s: + return cae::KeyCode::S; + case XK_t: + return cae::KeyCode::T; + case XK_u: + return cae::KeyCode::U; + case XK_v: + return cae::KeyCode::V; + case XK_w: + return cae::KeyCode::W; + case XK_x: + return cae::KeyCode::X; + case XK_y: + return cae::KeyCode::Y; + case XK_z: + return cae::KeyCode::Z; + + // Numbers + case XK_0: + return cae::KeyCode::Num0; + case XK_1: + return cae::KeyCode::Num1; + case XK_2: + return cae::KeyCode::Num2; + case XK_3: + return cae::KeyCode::Num3; + case XK_4: + return cae::KeyCode::Num4; + case XK_5: + return cae::KeyCode::Num5; + case XK_6: + return cae::KeyCode::Num6; + case XK_7: + return cae::KeyCode::Num7; + case XK_8: + return cae::KeyCode::Num8; + case XK_9: + return cae::KeyCode::Num9; + + // Modifiers + case XK_Shift_L: + return cae::KeyCode::LShift; + case XK_Shift_R: + return cae::KeyCode::RShift; + case XK_Control_L: + return cae::KeyCode::LCtrl; + case XK_Control_R: + return cae::KeyCode::RCtrl; + case XK_Alt_L: + return cae::KeyCode::LAlt; + case XK_Alt_R: + return cae::KeyCode::RAlt; + case XK_Super_L: + return cae::KeyCode::LSuper; + case XK_Super_R: + return cae::KeyCode::RSuper; + case XK_Caps_Lock: + return cae::KeyCode::CapsLock; + + // Navigation + case XK_Up: + return cae::KeyCode::Up; + case XK_Down: + return cae::KeyCode::Down; + case XK_Left: + return cae::KeyCode::Left; + case XK_Right: + return cae::KeyCode::Right; + case XK_Home: + return cae::KeyCode::Home; + case XK_End: + return cae::KeyCode::End; + case XK_Page_Up: + return cae::KeyCode::PageUp; + case XK_Page_Down: + return cae::KeyCode::PageDown; + + // Editing + case XK_Return: + return cae::KeyCode::Enter; + case XK_BackSpace: + return cae::KeyCode::Backspace; + case XK_Tab: + return cae::KeyCode::Tab; + case XK_space: + return cae::KeyCode::Space; + case XK_Delete: + return cae::KeyCode::Delete; + case XK_Insert: + return cae::KeyCode::Insert; + + // Function keys + case XK_F1: + return cae::KeyCode::F1; + case XK_F2: + return cae::KeyCode::F2; + case XK_F3: + return cae::KeyCode::F3; + case XK_F4: + return cae::KeyCode::F4; + case XK_F5: + return cae::KeyCode::F5; + case XK_F6: + return cae::KeyCode::F6; + case XK_F7: + return cae::KeyCode::F7; + case XK_F8: + return cae::KeyCode::F8; + case XK_F9: + return cae::KeyCode::F9; + case XK_F10: + return cae::KeyCode::F10; + case XK_F11: + return cae::KeyCode::F11; + case XK_F12: + return cae::KeyCode::F12; + + // System + case XK_Escape: + return cae::KeyCode::Escape; + case XK_Print: + return cae::KeyCode::PrintScreen; + case XK_Pause: + return cae::KeyCode::Pause; + case XK_Menu: + return cae::KeyCode::Menu; + + default: + return cae::KeyCode::Count; + } +} + bool cae::X11::create(const std::string &name, const WindowSize size) { m_display = XOpenDisplay(nullptr); @@ -29,8 +204,9 @@ bool cae::X11::create(const std::string &name, const WindowSize size) XStoreName(m_display, m_window, name.c_str()); - XSelectInput(m_display, m_window, ExposureMask | KeyPressMask | StructureNotifyMask); - + XSelectInput(m_display, m_window, + ExposureMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask | PointerMotionMask | + ButtonPressMask | ButtonReleaseMask); m_wmDeleteMessage = XInternAtom(m_display, "WM_DELETE_WINDOW", False); XSetWMProtocols(m_display, m_window, &m_wmDeleteMessage, 1); @@ -65,18 +241,19 @@ cae::WindowSize cae::X11::getWindowSize() const return {.width = static_cast(attrs.width), .height = static_cast(attrs.height)}; } -bool cae::X11::setIcon(const std::string &path) const +void cae::X11::setIcon(const std::string &path) const { if ((m_display == nullptr) || m_window == 0) { - return false; + utl::Logger::log("Failed to create window icon", utl::LogLevel::WARNING); + return; } try { const utl::Image image(path); - const auto pixelCount = static_cast(image.width * image.height); + const auto pixelCount = image.width * image.height; std::vector iconData; iconData.reserve(2 + pixelCount); @@ -84,12 +261,12 @@ bool cae::X11::setIcon(const std::string &path) const iconData.push_back(static_cast(image.height)); const uint8_t *pixels = image.pixels; - for (size_t i = 0; i < pixelCount; ++i) + for (size_t i = 0; std::cmp_less(i, pixelCount); ++i) { - const uint8_t r = pixels[i * 4 + 0]; - const uint8_t g = pixels[i * 4 + 1]; - const uint8_t b = pixels[i * 4 + 2]; - const uint8_t a = pixels[i * 4 + 3]; + const uint8_t r = pixels[(i * 4) + 0]; + const uint8_t g = pixels[(i * 4) + 1]; + const uint8_t b = pixels[(i * 4) + 2]; + const uint8_t a = pixels[(i * 4) + 3]; const unsigned long argb = (static_cast(a) << 24) | (static_cast(r) << 16) | (static_cast(g) << 8) | (static_cast(b)); @@ -104,61 +281,102 @@ bool cae::X11::setIcon(const std::string &path) const reinterpret_cast(iconData.data()), static_cast(iconData.size())); XFlush(m_display); - return true; } catch (const std::exception &e) { utl::Logger::log(std::string("Failed to set X11 window icon: ") + e.what(), utl::LogLevel::WARNING); - return false; } } bool cae::X11::shouldClose() const { return m_shouldClose; } -void cae::X11::pollEvents() +void cae::X11::pollEvents() {} + +bool cae::X11::pollEvent(WindowEvent &outEvent) { - while (XPending(m_display) != 0) + if (m_eventQueue.empty() && XPending(m_display) == 0) + { + return false; + } + + while (XPending(m_display) > 0) { XEvent event; XNextEvent(m_display, &event); + WindowEvent e{}; switch (event.type) { - case Expose: + case KeyPress: { - XGCValues gcValues; - GC gc = XCreateGC(m_display, m_window, 0, &gcValues); + e.type = WindowEventType::KeyDown; - XColor color; - const Colormap colormap = DefaultColormap(m_display, DefaultScreen(m_display)); - color.red = 0x0000; - color.green = 0x0000; - color.blue = 0x0000; - color.flags = DoRed | DoGreen | DoBlue; - XAllocColor(m_display, colormap, &color); + const KeySym sym = XkbKeycodeToKeysym(m_display, event.xkey.keycode, 0, 0); - XSetForeground(m_display, gc, color.pixel); + e.key.key = translateKeysym(sym); + m_eventQueue.push(e); + break; + } - XFillRectangle(m_display, m_window, gc, 0, 0, m_frameBufferSize.width, m_frameBufferSize.height); + case KeyRelease: + { + e.type = WindowEventType::KeyUp; + + const KeySym sym = XkbKeycodeToKeysym(m_display, event.xkey.keycode, 0, 0); - XFreeGC(m_display, gc); + e.key.key = translateKeysym(sym); + m_eventQueue.push(e); break; } + case ConfigureNotify: m_frameBufferResized = true; m_frameBufferSize.width = event.xconfigure.width; m_frameBufferSize.height = event.xconfigure.height; + e.type = WindowEventType::Resize; + e.resize.w = event.xconfigure.width; + e.resize.h = event.xconfigure.height; + m_eventQueue.push(e); break; + case ClientMessage: if (std::cmp_equal(event.xclient.data.l[0], m_wmDeleteMessage)) { m_shouldClose = true; + e.type = WindowEventType::Close; + m_eventQueue.push(e); } break; + + case MotionNotify: + e.type = WindowEventType::MouseMove; + e.mouseMove.x = event.xmotion.x; + e.mouseMove.y = event.xmotion.y; + m_eventQueue.push(e); + break; + + case ButtonPress: + case ButtonRelease: + e.type = + (event.type == ButtonPress) ? WindowEventType::MouseButtonDown : WindowEventType::MouseButtonUp; + e.mouseButton.button = static_cast(event.xbutton.button); + m_eventQueue.push(e); + break; + + case Expose: + break; + default: break; } } - XFlush(m_display); + if (!m_eventQueue.empty()) + { + outEvent = m_eventQueue.front(); + m_eventQueue.pop(); + return true; + } + + return false; } diff --git a/src/application.cpp b/src/application.cpp index d9c1e83..81401e7 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -114,12 +114,32 @@ void cae::Application::setupEngine(const std::string &rendererName, const std::s utl::Logger::log("No shader plugin found with name: " + shaderFrontendName, utl::LogLevel::WARNING); } m_engine = std::make_unique( - m_appConfig.engineConfig, []() { return nullptr; }, []() { return nullptr; }, []() { return nullptr; }, + m_appConfig.engineConfig, []() { return nullptr; }, []() { return nullptr; }, [rendererPlugin]() { return rendererPlugin; }, [shaderIRPlugin]() { return shaderIRPlugin; }, shaderFactories, [windowPlugin]() { return windowPlugin; }); } -void cae::Application::start() const +static const std::vector cubeVertices = { + // positions // colors + -0.5f, -0.5f, -0.5f, 1, 0, 0, 0.5f, -0.5f, -0.5f, 0, 1, 0, 0.5f, 0.5f, -0.5f, 0, 0, 1, + 0.5f, 0.5f, -0.5f, 0, 0, 1, -0.5f, 0.5f, -0.5f, 1, 1, 0, -0.5f, -0.5f, -0.5f, 1, 0, 0, + + -0.5f, -0.5f, 0.5f, 1, 0, 1, 0.5f, -0.5f, 0.5f, 0, 1, 1, 0.5f, 0.5f, 0.5f, 1, 1, 1, + 0.5f, 0.5f, 0.5f, 1, 1, 1, -0.5f, 0.5f, 0.5f, 0, 0, 0, -0.5f, -0.5f, 0.5f, 1, 0, 1, + + -0.5f, 0.5f, 0.5f, 1, 0, 0, -0.5f, 0.5f, -0.5f, 0, 1, 0, -0.5f, -0.5f, -0.5f, 0, 0, 1, + -0.5f, -0.5f, -0.5f, 0, 0, 1, -0.5f, -0.5f, 0.5f, 1, 1, 0, -0.5f, 0.5f, 0.5f, 1, 0, 0, + + 0.5f, 0.5f, 0.5f, 1, 0, 1, 0.5f, 0.5f, -0.5f, 0, 1, 1, 0.5f, -0.5f, -0.5f, 1, 1, 1, + 0.5f, -0.5f, -0.5f, 1, 1, 1, 0.5f, -0.5f, 0.5f, 0, 0, 0, 0.5f, 0.5f, 0.5f, 1, 0, 1, + + -0.5f, -0.5f, -0.5f, 1, 0, 0, 0.5f, -0.5f, -0.5f, 0, 1, 0, 0.5f, -0.5f, 0.5f, 0, 0, 1, + 0.5f, -0.5f, 0.5f, 0, 0, 1, -0.5f, -0.5f, 0.5f, 1, 1, 0, -0.5f, -0.5f, -0.5f, 1, 0, 0, + + -0.5f, 0.5f, -0.5f, 1, 0, 1, 0.5f, 0.5f, -0.5f, 0, 1, 1, 0.5f, 0.5f, 0.5f, 1, 1, 1, + 0.5f, 0.5f, 0.5f, 1, 1, 1, -0.5f, 0.5f, 0.5f, 0, 0, 0, -0.5f, 0.5f, -0.5f, 1, 0, 1}; + +void cae::Application::start() { static const std::vector shaderSources = { {.id = "basic_vertex", @@ -132,9 +152,8 @@ void cae::Application::start() const .source = utl::fileToString(utl::Path::resolveRelativeToExe("assets/shaders/glsl/texture.frag")), .stage = ShaderStage::FRAGMENT}, }; - m_engine->initializeRenderResources( - shaderSources, std::vector{-0.5F, -0.5F, 1.F, 0.F, 0.F, 0.5F, -0.5F, 0.F, 1.F, 0.F, 0.F, 0.5F, 0.F, 0.F, 1.F}); - m_engine->run(); + m_engine->initializeRenderResources(shaderSources, cubeVertices); + mainLoop(); } void cae::Application::stop() @@ -144,3 +163,90 @@ void cae::Application::stop() m_pluginLoader = nullptr; m_engine = nullptr; } + +void cae::Application::mainLoop() +{ + std::array fpsBuffer{}; + int fpsIndex = 0; + WindowEvent e{}; + + while (!m_engine->getWindow()->shouldClose()) + { + m_engine->render(); + glm::vec3 moveDir(0.0F); + glm::vec2 lookDir(0.0F); + m_engine->getWindow()->pollEvents(); + while (m_engine->getWindow()->pollEvent(e)) + { + if (e.type == WindowEventType::KeyDown) + { + m_keyState[e.key.key] = true; + } + else if (e.type == WindowEventType::KeyUp) + { + m_keyState[e.key.key] = false; + } + } + + if (m_keyState[KeyCode::Up]) + { + lookDir.y += 1.0F; + } + if (m_keyState[KeyCode::Down]) + { + lookDir.y -= 1.0F; + } + if (m_keyState[KeyCode::Left]) + { + lookDir.x -= 1.0F; + } + if (m_keyState[KeyCode::Right]) + { + lookDir.x += 1.0F; + } + + if (glm::length(lookDir) > 0.0F) + { + lookDir *= m_engine->getCamera()->getLookSpeed() * m_engine->getClock()->getDeltaSeconds(); + m_engine->getCamera()->rotate(lookDir.x, lookDir.y, 1.0F); + } + + glm::vec3 forward = glm::normalize( + glm::vec3(m_engine->getCamera()->getDirection().x, 0.0F, m_engine->getCamera()->getDirection().z)); + glm::vec3 right = glm::normalize(glm::cross(forward, glm::vec3(0.0F, 1.0F, 0.0F))); + + if (m_keyState[KeyCode::W]) + { + moveDir += forward; + } + if (m_keyState[KeyCode::S]) + { + moveDir -= forward; + } + if (m_keyState[KeyCode::A]) + { + moveDir -= right; + } + if (m_keyState[KeyCode::D]) + { + moveDir += right; + } + + if (glm::length(moveDir) > 0.0F) + { + moveDir = glm::normalize(moveDir); + m_engine->getCamera()->move(moveDir, m_engine->getClock()->getDeltaSeconds()); + } + + if (m_keyState[KeyCode::LCtrl]) + { + m_engine->getCamera()->move(glm::vec3(0.0F, -1.0F, 0.0F), m_engine->getClock()->getDeltaSeconds()); + } + if (m_keyState[KeyCode::Space]) + { + m_engine->getCamera()->move(glm::vec3(0.0F, 1.0F, 0.0F), m_engine->getClock()->getDeltaSeconds()); + } + + m_engine->update(fpsBuffer, fpsIndex); + } +} diff --git a/src/conf.cpp b/src/conf.cpp index 95037cf..4013e7a 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -11,7 +11,7 @@ using json = nlohmann::json; cae::EngineConfig cae::Application::parseEngineConf(const std::string &path) { - auto confPath = utl::Path::resolveRelativeToExe(path); + auto confPath = utl::Path::resolveRelativeToCwd(path); if (!utl::Path::existsFile(confPath)) { utl::Logger::log("Config file does not exist: " + confPath.string(), utl::LogLevel::WARNING); @@ -50,6 +50,60 @@ cae::EngineConfig cae::Application::parseEngineConf(const std::string &path) config.audio_muted = audio["muted"]; } } + if (j.contains("camera")) + { + const auto &camera = j["camera"]; + if (camera.contains("position") && camera["position"].is_array() && camera["position"].size() == 3) + { + if (const auto &position = camera["position"]; + position[0].is_number_float() && position[1].is_number_float() && position[2].is_number_float()) + { + config.camera_position.x = position[0]; + config.camera_position.y = position[1]; + config.camera_position.z = position[2]; + } + } + if (camera.contains("rotation") && camera["rotation"].is_array() && camera["rotation"].size() == 3) + { + if (const auto &rotation = camera["rotation"]; + rotation[0].is_number_float() && rotation[1].is_number_float() && rotation[2].is_number_float()) + { + config.camera_rotation.x = rotation[0]; + config.camera_rotation.y = rotation[1]; + config.camera_rotation.z = rotation[2]; + } + } + if (camera.contains("direction") && camera["direction"].is_array() && camera["direction"].size() == 3) + { + if (const auto &direction = camera["direction"]; + direction[0].is_number_float() && direction[1].is_number_float() && direction[2].is_number_float()) + { + config.camera_direction.x = direction[0]; + config.camera_direction.y = direction[1]; + config.camera_direction.z = direction[2]; + } + } + if (camera.contains("movementSpeed") && camera["movementSpeed"].is_number_float()) + { + config.camera_move_speed = camera["movementSpeed"]; + } + if (camera.contains("rotationSpeed") && camera["rotationSpeed"].is_number_float()) + { + config.camera_look_speed = camera["rotationSpeed"]; + } + if (camera.contains("fov") && camera["fov"].is_number_unsigned()) + { + config.camera_fov = camera["fov"]; + } + if (camera.contains("nearPlane") && camera["nearPlane"].is_number_float()) + { + config.camera_near_plane = camera["nearPlane"]; + } + if (camera.contains("farPlane") && camera["farPlane"].is_number_float()) + { + config.camera_far_plane = camera["farPlane"]; + } + } if (j.contains("log")) { if (const auto &log = j["log"]; log.contains("fps") && log["fps"].is_boolean()) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 86b8fbc..7eb2560 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,11 +20,10 @@ if (BUILD_CAE_TESTS) add_executable(${PROJECT_NAME} ${SOURCES}) - target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest_main) + target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest_main cae-compile-options) target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDE_DIR}) include(GoogleTest) gtest_discover_tests(${PROJECT_NAME}) - target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_23) set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) endif()