diff --git a/CMakeLists.txt b/CMakeLists.txt index d1ab2c7..df796ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,7 @@ # Nous voulons un cmake "récent" pour utiliser les dernières fonctionnalités. cmake_minimum_required(VERSION 3.20) set (CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_COMPILER clang++) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") # Nom du projet. set(PROJECT CosmicEngine) project(${PROJECT}) @@ -42,15 +41,6 @@ endif() # ---------- Inclusion des packages sous linux ----------- if(UNIX) -# --------- Inclusion d'OpenGL ---------- -# OpenGL Lib pour charger OpenGL, fournit avec les drivers, donc se trouve toute seul. - # find_package(OpenGL REQUIRED) - # if(OPENGL_FOUND) - # message("lib OpenGL Trouvé") - # else() - # message("lib OpenGL Introuvable") - # endif() -# --------------------------------------- # ---------- Inclusion de GLM ----------- # GLM Lib pour mathématique, en mode header only. @@ -86,129 +76,6 @@ if(UNIX) message("lib EnTTlib Introuvable") endif() - -# --------- Inclusion de Boost ---------- -# Boost Lib pour diverse simplification - # set(Boost_USE_STATIC_LIBS OFF) - # set(Boost_USE_MULTITHREADED ON) - # set(Boost_USE_STATIC_RUNTIME OFF) - - # find_package(Boost REQUIRED COMPONENTS log_setup log filesystem chrono thread date_time regex) # header only libraries must not be added here - - # message(STATUS "Boost version: ${Boost_VERSION}") - - # if(NOT TARGET Boost::filesystem) - # add_library(Boost::filesystem IMPORTED INTERFACE) - # set_property(TARGET Boost::filesystem PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::filesystem PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::thread) - # add_library(Boost::thread IMPORTED INTERFACE) - # set_property(TARGET Boost::thread PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::thread PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::chrono) - # add_library(Boost::chrono IMPORTED INTERFACE) - # set_property(TARGET Boost::chrono PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::chrono PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::date_time) - # add_library(Boost::date_time IMPORTED INTERFACE) - # set_property(TARGET Boost::date_time PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::date_time PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::regex) - # add_library(Boost::regex IMPORTED INTERFACE) - # set_property(TARGET Boost::regex PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::regex PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::log) - # add_library(Boost::log IMPORTED INTERFACE) - # set_property(TARGET Boost::log PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::log PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(NOT TARGET Boost::log_setup) - # add_library(Boost::log_setup IMPORTED INTERFACE) - # set_property(TARGET Boost::log_setup PROPERTY - # INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIR}) - # set_property(TARGET Boost::log_setup PROPERTY - # INTERFACE_LINK_LIBRARIES ${Boost_LIBRARIES}) - # endif() - - # if(Boost_FOUND) - # message("lib Boost Trouvé") - # else() - # message("lib Boost Introuvable") - # endif() -# --------------------------------------- - -# -------- Inclusion de la SDL2 ---------- -# SDL2 Lib pour fenetre et contrôle - -# Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - # find_package(SDL2 REQUIRED) - # if(SDL2_FOUND) - # message("lib SDL2 Trouvé") - # else() - # message("lib SDL2 Introuvable") - # endif() -# --------------------------------------- - -# ------- Inclusion de SDL2_IMAGE -------- -# SDL2_IMAGE Lib pour charger une image - # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - # find_package(SDL2_image QUIET) - # #find_library(SDL2_image libSDL2_image) - - # if(SDL2_image_FOUND) - # message("lib SDL2_IMAGE Trouvé") - # else() - # message("lib SDL2_IMAGE Introuvable") - # endif() -# --------------------------------------- - -# ------- Inclusion de SDL2_TTF -------- -# SDL2_IMAGE Lib pour charger une police d'écriture. - # set(SDL2_ttf_DIR ./lib/CMake/Linux) - # # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - # find_package(SDL2_ttf QUIET) - # #find_library(SDL2_ttf libSDL2_ttf) - # if(SDL2_ttf_FOUND) - # message("lib SDL2_TTF Trouvé") - # else() - # message("lib SDL2_TTF Introuvable") - # endif() -# --------------------------------------- - -# --------- Inclusion de GLEW ----------- -# GLEW Lib pour charger utiliser OpenGL + extension - # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - # find_package(GLEW REQUIRED) - # if(GLEW_FOUND) - # message("lib GLEW Trouvé") - # else() - # message("lib GLEW Introuvable") - # endif() -# --------------------------------------- - # ---------- Inclusion de ASSIMP ----------- # Assimp Lib import modèles 3D. find_package(assimp REQUIRED) @@ -219,31 +86,6 @@ if(UNIX) endif() # --------------------------------------- -# ---------- Inclusion de ODE ----------- -# ODE Lib Moteur physique. - # set(ODE_DIR ./lib/CMake/Linux) - # # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - # find_package(ODE REQUIRED) - # if(ODE_FOUND) - # message("lib ODE Trouvé") - # else() - # message("lib ODE Introuvable") - # endif() -# --------------------------------------- - -# --------- Inclusion de SNDFILE ---------- -# SNDFILE Lib pour inclure le son. - # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. - #set(SNDFILE_DIR ./lib/CMake/Linux) - # find_package(sndfile QUIET)#TODO corrige - # #find_library(sndfile libsndfile) - # if(sndfile_FOUND) - # message("lib SNDFILE Trouvé") - # else() - # message("lib SNDFILE Introuvable") - # endif() -# --------------------------------------- - # ---------- Inclusion de OpenAL----------- # OpenAL Lib gérer le son. # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. @@ -329,22 +171,6 @@ endif() endif() # --------------------------------------- -# ------- Inclusion de Spirv-cross -------- -#Spirv-cross pour metadonnees shader spirv -# set(spirv_cross_core_DIR ./lib/CMake/Linux/spirv-crossConf) -# set(spirv_cross_glsl_DIR ./lib/CMake/Linux/spirv-crossConf) - # Les autre plateforme (Linux...) ont un installateur de paquet, la lib se trouve toute seul. -# find_package(spirv_cross_core QUIET) -# find_package(spirv_cross_glsl QUIET) - - #find_library(SDL2_ttf libSDL2_ttf) -# if(spirv_cross_core_FOUND AND spirv_cross_glsl_FOUND) -# message("lib spirv_cross Trouvé") -# else() -# message("lib spirv_cross Introuvable") -# endif() -# --------------------------------------- - # ------- Inclusion de Spirv-cross -------- #Spirv-cross pour metadonnees shader spirv set(spirvreflectlib_DIR ./lib/CMake/Linux/) @@ -401,6 +227,20 @@ else() endif() # --------------------------------------- +# ------- Inclusion de MSDFATLASGEN -------- +# Pour les font +set(MsdfAtlasGen_DIR ./lib/CMake/Linux) + +find_package(MsdfAtlasGen REQUIRED) + +if(MsdfAtlasGen_FOUND) + message("lib MsdfAtlasGen Trouvé") +else() + message("lib MsdfAtlasGen Introuvable") +endif() +# --------------------------------------- + + endif() @@ -447,6 +287,22 @@ target_include_directories(Engine ${CMAKE_CURRENT_SOURCE_DIR}/src/Engine ) +add_library(EngineHeaders INTERFACE) +target_include_directories(EngineHeaders INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/src/Engine + ${GLM_INCLUDE_DIRS} + ${JSONFMCPP_INCLUDE_DIRS} + ${ENTT_INCLUDE_DIRS} + ${JOLT_INCLUDE_DIRS} + ${VMA_INCLUDE_DIRS} + ${DRLIBS_INCLUDE_DIRS} + ${MSDFATLASGEN_INCLUDE_DIRS} + ${OPENAL_INCLUDE_DIR} + ${SPIRV_REFLECT_INCLUDE_DIRS} + ${ASSIMP_INCLUDE_DIRS} + ${JSONVALIDATOR_INCLUDE_DIRS} +) + add_library(ScriptModule SHARED ${SRCS_SCRIPTS}) target_include_directories(ScriptModule PRIVATE ${HEADERS_ENGINE}) @@ -471,135 +327,68 @@ if(GENERATED_SPV_FILES) ) endif() -add_dependencies(${PROJECT} Engine) +add_dependencies(${PROJECT} EngineHeaders) add_dependencies(Engine CompileSlangShaders) -add_dependencies(ScriptModule Engine) +add_dependencies(ScriptModule EngineHeaders) -target_link_libraries(CosmicTest PRIVATE Catch2::Catch2WithMain Engine) -# Fichier include -# OpenGL -#include_directories(${OPENGL_INCLUDE_DIR}) -# SDL2 -#include_directories(${SDL2_INCLUDE_DIRS}) -# GLEW -#include_directories(${GLEW_INCLUDE_DIRS}) -# SDL2_image -#include_directories(${SDL2_IMAGE_INCLUDE_DIRS}) -# SDL2_ttf -#include_directories(${SDL2_TTF_INCLUDE_DIRS}) -# GLM include_directories(${GLM_INCLUDE_DIRS}) -# JSONFMCPP include_directories(${JSONFMCPP_INCLUDE_DIRS}) -#ENTT include_directories(${ENTT_INCLUDE_DIRS}) -#include_directories(${SPIRV_INCLUDE_DIRS}) include_directories(${SPIRV_REFLECT_INCLUDE_DIRS}) include_directories(${VMA_INCLUDE_DIRS}) - -# ASSIMP include_directories(${ASSIMP_INCLUDE_DIRS}) -# ODE -#include_directories(${ODE_INCLUDE_DIRS}) include_directories(${JOLT_INCLUDE_DIRS}) -# SNDFILE -#include_directories(${SNDFILE_INCLUDE_DIRS}) -# OPENAL -include_directories(${OPENAL_INCLUDE_DIRS}) +include_directories(${OPENAL_INCLUDE_DIR}) include_directories(${JSONVALIDATOR_INCLUDE_DIRS}) include_directories(${DRLIBS_INCLUDE_DIRS}) -target_link_libraries(Engine ${JSONVALIDATOR_LIBRARIES}) +include_directories(${MSDFATLASGEN_INCLUDE_DIRS}) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - target_compile_definitions(Engine PRIVATE - JPH_ENABLE_ASSERTS - JPH_PROFILE_ENABLED - JPH_OBJECT_STREAM - JPH_DEBUG_RENDERER - ) +target_compile_definitions(Engine PRIVATE +JPH_ENABLE_ASSERTS +JPH_PROFILE_ENABLED +JPH_OBJECT_STREAM +JPH_DEBUG_RENDERER +) - target_compile_definitions(ScriptModule PRIVATE - JPH_ENABLE_ASSERTS - JPH_PROFILE_ENABLED - JPH_OBJECT_STREAM - JPH_DEBUG_RENDERER - ) +#target_compile_definitions(ScriptModule PRIVATE +# JPH_ENABLE_ASSERTS +# JPH_PROFILE_ENABLED +# JPH_OBJECT_STREAM +# JPH_DEBUG_RENDERER +#) else() # Release - target_compile_definitions(Engine PRIVATE - JPH_OBJECT_STREAM - ) - target_compile_definitions(ScriptModule PRIVATE - JPH_OBJECT_STREAM - ) +target_compile_definitions(Engine PRIVATE +JPH_OBJECT_STREAM +) +#target_compile_definitions(ScriptModule PRIVATE +# JPH_OBJECT_STREAM +#) endif() -target_link_libraries(Engine +target_link_libraries(Engine PRIVATE debug ${JOLT_LIBRARIES_DEBUG} optimized ${JOLT_LIBRARIES_RELEASE} + SDL3::SDL3 + SDL3_image + SDL3_ttf + Vulkan::Vulkan + spirv-reflect + ${ASSIMP_LIBRARIES} + OpenAL::OpenAL + ${JSONVALIDATOR_LIBRARIES} + ${MSDFATLASGEN} ) -# Fichier lib -# OpenGL -#target_link_libraries(Engine OpenMP::OpenMP_CXX) -# OpenMP -#target_link_libraries(Engine ${OPENGL_LIBRARIES}) - -# SDL2 -#target_link_libraries(Engine ${SDL2_LIBRARIES}) -target_link_libraries(Engine SDL3::SDL3) -# GLEW -#target_link_libraries(Engine ${GLEW_LIBRARIES}) - -# SDL2_image -#target_link_libraries(Engine SDL2_image) -target_link_libraries(Engine SDL3_image) - -# SDL2_ttf -#target_link_libraries(Engine SDL2_ttf) -target_link_libraries(Engine SDL3_ttf) -# Boost - -#Vulkan -target_link_libraries(Engine Vulkan::Vulkan) - -target_link_libraries(Engine spirv-reflect) - -#target_link_libraries(Engine spirv-cross-glsl spirv-cross-core) - -# ASSIMP -target_link_libraries(Engine ${ASSIMP_LIBRARIES}) - -# ODE -#target_link_libraries(Engine ${ODE_LIBRARIES}) - - - -# SNDFILE -#target_link_libraries(Engine sndfile) - -# OPENAL -target_link_libraries(Engine OpenAL::OpenAL) - - -#target_link_libraries(Engine ${CMAKE_DL_LIBS}) - -#target_link_libraries(${PROJECT} ${CMAKE_DL_LIBS}) - - -# Boost -# target_link_libraries(Engine Boost::boost) -# target_link_libraries(Engine Boost::filesystem) -# target_link_libraries(Engine Boost::chrono) -# target_link_libraries(Engine Boost::thread) -# target_link_libraries(Engine Boost::date_time) -# target_link_libraries(Engine Boost::regex) -# target_link_libraries(Engine Boost::log) -# target_link_libraries(Engine Boost::log_setup) - -target_link_libraries(ScriptModule Engine) -target_link_libraries(${PROJECT} Engine) +target_link_libraries(CosmicTest PRIVATE Catch2::Catch2WithMain Engine EngineHeaders) +target_link_libraries(ScriptModule PRIVATE EngineHeaders) +target_link_options(ScriptModule PRIVATE -Wl,--allow-shlib-undefined) +target_link_libraries(${PROJECT} PUBLIC Engine EngineHeaders) +target_link_options(${PROJECT} PRIVATE + -Wl,--export-dynamic +) if(UNIX) add_custom_command( diff --git a/lib/All/msdf-atlas-gen b/lib/All/msdf-atlas-gen new file mode 160000 index 0000000..2ede254 --- /dev/null +++ b/lib/All/msdf-atlas-gen @@ -0,0 +1 @@ +Subproject commit 2ede254314a2512252a225fa6c975948d6af559a diff --git a/lib/CMake/Linux/MsdfAtlasGenConfig.cmake b/lib/CMake/Linux/MsdfAtlasGenConfig.cmake new file mode 100644 index 0000000..385ef8b --- /dev/null +++ b/lib/CMake/Linux/MsdfAtlasGenConfig.cmake @@ -0,0 +1,5 @@ +set(MSDFATLASGEN "${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/artery-font-format/artery-font; ${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/msdf-atlas-gen; ${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/msdfgen/ext; {CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/msdfgen/core") + +set(MSDFGENEXT "${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/msdfgen/libmsdfgen-ext.a") +set(MSDFGENCORE "${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/msdfgen/libmsdfgen-core.a") +set(MSDFATLASGEN "${CMAKE_CURRENT_SOURCE_DIR}/lib/All/msdf-atlas-gen/libmsdf-atlas-gen.a") diff --git a/src/Engine/Core/Component/Camera/CCamera2D.cpp b/src/Engine/Core/Component/Camera/CCamera2D.cpp new file mode 100644 index 0000000..9d6a950 --- /dev/null +++ b/src/Engine/Core/Component/Camera/CCamera2D.cpp @@ -0,0 +1,15 @@ +#include "CCamera2D.hpp" +#include "Core/Kernel/CKernel.hpp" + +namespace CosmicCore { + void CCamera2D::recalcProjection() { + //todo + float width = CKernelBase::instance()->getWindowWidth(); + float height = CKernelBase::instance()->getWindowHeight(); + //m_projection = glm::ortho(0.0f, width, 0.0f, height, -1.0f, 1.0f); + //m_projection //= glm::perspective(glm::radians(m_fov), m_aspect, m_near, m_far); + m_projection = glm::ortho(0.0f, width, height, 0.0f, -1.0f, 1.0f); + + //m_projection[1][1] *= -1; + } +} \ No newline at end of file diff --git a/src/Engine/Core/Component/Camera/CCamera2D.hpp b/src/Engine/Core/Component/Camera/CCamera2D.hpp new file mode 100644 index 0000000..3d94e8f --- /dev/null +++ b/src/Engine/Core/Component/Camera/CCamera2D.hpp @@ -0,0 +1,117 @@ +#ifndef CCAMERA2D_HPP +#define CCAMERA2D_HPP + +#include "../CAbstractComponent.hpp" +//pour vulkan depth 0-1 (opengl [-1,1]) +#include +#include +#include "../../Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp" +#include "../Geometry/CTransform2D.hpp" +namespace CosmicCore { + + //TODO LES MAJ REELLES DUN MOUVEMENT TRANSFORM + //AJOUT DONC DE LA VUE ET AUTRE PARAM + //Pour le moment ne gère qu'une caméra fixe (UI) +class CCamera2D : public CAbstractComponent { +private: + glm::mat4 m_projection = glm::mat4(1.0f); + + // GPU + struct Camera2DUBOData { + glm::mat4 projection; + }; + + std::array m_uniformBuffers; + std::array m_mappedData{}; + std::array m_descriptorSets; + + void recalcProjection(); + +public: + CCamera2D(CEntity& entity) : CAbstractComponent(entity) { + recalcProjection(); + } + + ~CCamera2D(){ + destroy(); + } + + glm::mat4 getProjection() const { return m_projection; } + + // GPU + void initUniformBuffer(VmaAllocator allocator) { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = sizeof(Camera2DUBOData); + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + + VmaAllocationCreateInfo allocInfo{}; + allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VmaAllocationInfo info{}; + vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, + &m_uniformBuffers[i].buffer, + &m_uniformBuffers[i].allocation, + &info); + m_mappedData[i] = info.pMappedData; + + m_descriptorSets[i] = api->getDescriptorPoolManager().allocate( + *api->getProjection2DLayout() + ); + + vk::DescriptorBufferInfo descriptorBufferInfo{ + vk::Buffer(m_uniformBuffers[i].buffer), + 0, + sizeof(Camera2DUBOData) + }; + vk::WriteDescriptorSet descriptorWrite{ + *m_descriptorSets[i].set, + 0, 0, 1, + vk::DescriptorType::eUniformBuffer, + {}, &descriptorBufferInfo + }; + static_cast(api->getDevice())->updateDescriptorSets(descriptorWrite, {}); + } + } + + void destroyUniformBuffer(VmaAllocator allocator) { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + api->getDescriptorPoolManager().free(m_descriptorSets[i]); + vmaDestroyBuffer(allocator, m_uniformBuffers[i].buffer, + m_uniformBuffers[i].allocation); + } + } + + void updateUniformBuffer(uint32_t frameIndex, const CTransform2D& transform) { + + Camera2DUBOData data{ m_projection}; + memcpy(m_mappedData[frameIndex], &data, sizeof(data)); + } + + vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) { + return m_descriptorSets[frameIndex].set; + } + + void destroy() + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + + api->destroyBuffer(m_uniformBuffers[i], api->getCurrentFrameIndex()); + api->destroyDescriptorSet(m_descriptorSets[i], api->getCurrentFrameIndex()); + } + } + + nlohmann::json to_json(){ + return nlohmann::json(); + }; +}; + +} // namespace CosmicCore +#endif \ No newline at end of file diff --git a/src/Engine/Core/Component/Collider/CCollider2D.cpp b/src/Engine/Core/Component/Collider/CCollider2D.cpp new file mode 100644 index 0000000..2f6ec09 --- /dev/null +++ b/src/Engine/Core/Component/Collider/CCollider2D.cpp @@ -0,0 +1,24 @@ +#include "CCollider2D.hpp" +#include "Core/Component/Geometry/CTransform2D.hpp" +#include "Core/Kernel/CKernel.hpp" + +namespace CosmicCore { + bool CCollider2D::shapeContains(glm::vec2 point) const { + auto& registry = getEntity().getRegistry(); + + // récupère le transform + auto& transform = registry.registry.get(*getEntity()); + + glm::vec2 abs = transform.getAbsolutePosition(); + float y = CKernelBase::instance()->getWindowHeight(); + switch (m_shape) { + + case E2DShape::RECTANGLE: return point.x >= abs.x && point.x <= abs.x + transform.getSize().x && (y-point.y) >= abs.y && (y-point.y) <= abs.y + transform.getSize().y; + case E2DShape::CIRCLE: break;//TODO + case E2DShape::TEXT: break; + case E2DShape::POLYGON: break; + break; + } + return false; + } +} \ No newline at end of file diff --git a/src/Engine/Core/Component/Collider/CCollider2D.hpp b/src/Engine/Core/Component/Collider/CCollider2D.hpp new file mode 100644 index 0000000..d322fcf --- /dev/null +++ b/src/Engine/Core/Component/Collider/CCollider2D.hpp @@ -0,0 +1,31 @@ +#ifndef CCOLLIDER2D_HPP +#define CCOLLIDER2D_HPP + +#include "Core/Component/CAbstractComponent.hpp" +#include "Core/Entity/CEntity.hpp" +#include "glm/ext/vector_float2.hpp" +namespace CosmicCore { + + enum class E2DShape + { + RECTANGLE, + CIRCLE, + TEXT, + POLYGON + }; + + class CCollider2D: public CAbstractComponent + { + private: + E2DShape m_shape = E2DShape::RECTANGLE; + public: + CCollider2D(CEntity& entity, E2DShape shape): CAbstractComponent(entity), m_shape(shape){}; + + bool shapeContains(glm::vec2 point) const; + nlohmann::json to_json(){return nlohmann::json();}; + + }; + +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Component/Geometry/CTransform.cpp b/src/Engine/Core/Component/Geometry/CTransform.cpp index e858c08..f7ace30 100644 --- a/src/Engine/Core/Component/Geometry/CTransform.cpp +++ b/src/Engine/Core/Component/Geometry/CTransform.cpp @@ -78,6 +78,7 @@ namespace CosmicCore return parentTransform.getInheritedTransformation() * m_transformation; } + glm::vec3 CTransform::getCenter(void) const { return m_center; } diff --git a/src/Engine/Core/Component/Geometry/CTransform2D.cpp b/src/Engine/Core/Component/Geometry/CTransform2D.cpp new file mode 100644 index 0000000..b16ae06 --- /dev/null +++ b/src/Engine/Core/Component/Geometry/CTransform2D.cpp @@ -0,0 +1,64 @@ +#include "CTransform2D.hpp" +#include "Core/Kernel/CKernel.hpp" +#include "Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp" +#include + +namespace CosmicCore { + void CTransform2D::initUniformBuffer(VmaAllocator allocator) + { + if(m_gpuInitialized) return; + + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = sizeof(Transform2DUBO); + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + + VmaAllocationCreateInfo allocInfo{}; + allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; + allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VmaAllocationInfo info{}; + vmaCreateBuffer(allocator, &bufferInfo, &allocInfo, + &m_uniformBuffers[i].buffer, + &m_uniformBuffers[i].allocation, + &info); + m_mappedData[i] = info.pMappedData; + + m_descriptorSets[i] = api->getDescriptorPoolManager().allocate(api->getTransform2DLayout()); + + vk::DescriptorBufferInfo descriptorBufferInfo{vk::Buffer(m_uniformBuffers[i].buffer), 0, sizeof(Transform2DUBO)}; + vk::WriteDescriptorSet descriptorWrite{m_descriptorSets[i].set, 0, 0,1, vk::DescriptorType::eUniformBuffer, {}, &descriptorBufferInfo}; + static_cast(api->getDevice())->updateDescriptorSets(descriptorWrite, {}); + } + m_gpuInitialized = true; + } + + void CTransform2D::destroyUniformBuffer() + { + if(!m_gpuInitialized) return; + + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + + api->destroyBuffer(m_uniformBuffers[i], api->getCurrentFrameIndex()); + api->destroyDescriptorSet(m_descriptorSets[i], api->getCurrentFrameIndex()); + } + } + + void CTransform2D::updateUniformBuffer(uint32_t frameIndex) + { + if (!m_gpuInitialized) return; + Transform2DUBO data{ + getMatrix(), + m_size, + m_zOrder, + 0.0f + }; + memcpy(m_mappedData[frameIndex], &data, sizeof(data)); + } + +} \ No newline at end of file diff --git a/src/Engine/Core/Component/Geometry/CTransform2D.hpp b/src/Engine/Core/Component/Geometry/CTransform2D.hpp new file mode 100644 index 0000000..749b5e6 --- /dev/null +++ b/src/Engine/Core/Component/Geometry/CTransform2D.hpp @@ -0,0 +1,109 @@ +#ifndef CTRANSFORM2D_HPP +#define CTRANSFORM2D_HPP + +#include "Core/Component/CAbstractComponent.hpp" +#include "Core/Systems/Graphics/API/VulkanImplementation/ManagedDescriptorSet.hpp" +#include "Core/Systems/Graphics/API/VulkanImplementation/VMABuffer.hpp" +#include "glm/ext/matrix_float4x4.hpp" +#include "glm/ext/vector_float2.hpp" +#include "glm/gtx/transform.hpp" + +namespace CosmicCore { + + struct Transform2DUBO { + glm::mat4 transform; // matrice 2D + glm::vec2 size; // taille pour le shader SDF + float zOrder; + float padding; + }; + + class CTransform2D : public CAbstractComponent { + glm::vec2 m_position = {0, 0}; + glm::vec2 m_size = {100, 100}; + glm::vec2 m_scale = {1, 1}; // scale indépendant de la taille + glm::vec2 m_anchor = {0, 0}; // 0=topleft, 0.5=center, 1=bottomright + glm::vec2 m_pivot = {0, 0}; + float m_rotation = 0.0f; + float m_zOrder = 0.0f; // ordre de rendu UI + bool m_visible = true; + + //TODO RELATIONSHIP2D ??? + CTransform2D* m_parent = nullptr; // séparé de CRelationship 3D + + std::array m_uniformBuffers; + std::array m_mappedData{}; + std::array m_descriptorSets; + bool m_gpuInitialized = false; + + public: + explicit CTransform2D(CEntity& entity) : CAbstractComponent(entity) {} + + ~CTransform2D() { + if (m_gpuInitialized) destroyUniformBuffer(); + } + + CTransform2D(CTransform2D&&) = default; + CTransform2D& operator=(CTransform2D&&) = default; + CTransform2D(const CTransform2D&) = delete; + CTransform2D& operator=(const CTransform2D&) = delete; + + CTransform2D& setPosition(glm::vec2 pos) { m_position = pos; return *this; } + CTransform2D& setSize(glm::vec2 size) { m_size = size; return *this; } + CTransform2D& setScale(glm::vec2 scale) { m_scale = scale;return *this; } + CTransform2D& setRotation(float rot) { m_rotation = rot; return *this; } + CTransform2D& setZOrder(float z) { m_zOrder = z; return *this; } + CTransform2D& setVisible(bool v) { m_visible = v; return *this; } + CTransform2D& setAnchor(glm::vec2 anchor) { m_anchor = anchor; return *this; } + CTransform2D& setPivot(glm::vec2 pivot) { m_pivot = pivot; return *this; } + CTransform2D& setParent(CTransform2D* p) { m_parent = p; return *this; } + + glm::vec2 getPosition() const { return m_position; } + glm::vec2 getSize() const { return m_size; } + glm::vec2 getScale() const { return m_scale; } + float getRotation() const { return m_rotation; } + float getZOrder() const { return m_zOrder; } + bool isVisible() const { return m_visible; } + CTransform2D* getParent() const { return m_parent; } + + + glm::vec2 getAbsolutePosition() const { + glm::vec2 base = m_position; + /*if (m_parent) { + glm::vec2 parentPos = m_parent->getAbsolutePosition(); + glm::vec2 parentSize = m_parent->getSize(); + // anchor relatif à la taille du parent + base = parentPos + m_anchor * parentSize + m_position; + }*/ + return base; + } + + + + glm::mat4 getMatrix() const { + glm::vec2 absPos = getAbsolutePosition(); + glm::vec2 pivotPx = m_pivot * m_size; + + glm::mat4 mat = glm::mat4(1.0f); + mat = glm::translate(mat, glm::vec3(absPos + pivotPx, m_zOrder * 0.001f)); + mat = glm::rotate(mat, glm::radians(m_rotation), {0, 0, 1}); + mat = glm::scale(mat, glm::vec3(m_size * m_scale, 1)); + mat = glm::translate(mat, glm::vec3(-m_pivot, 0)); + return mat; + } + + // ── GPU ─────────────────────────────────────────────────────────── + void initUniformBuffer(VmaAllocator allocator); + void destroyUniformBuffer(); + void updateUniformBuffer(uint32_t frameIndex); + + vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) { + return m_descriptorSets[frameIndex].set; + } + + nlohmann::json to_json() { + return {}; + } + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Component/Graphics/CRenderer2D.cpp b/src/Engine/Core/Component/Graphics/CRenderer2D.cpp new file mode 100644 index 0000000..0779df8 --- /dev/null +++ b/src/Engine/Core/Component/Graphics/CRenderer2D.cpp @@ -0,0 +1,5 @@ +#include "CRenderer2D.hpp" + +namespace CosmicCore { + +} // namespace CosmicCore \ No newline at end of file diff --git a/src/Engine/Core/Component/Graphics/CRenderer2D.hpp b/src/Engine/Core/Component/Graphics/CRenderer2D.hpp new file mode 100644 index 0000000..2bb159a --- /dev/null +++ b/src/Engine/Core/Component/Graphics/CRenderer2D.hpp @@ -0,0 +1,21 @@ +#ifndef CUIRENDERER_HPP +#define CUIRENDERER_HPP + +#include "CAbstractRenderer.hpp" +#include "Core/Entity/CEntity.hpp" +#include "Core/Systems/Graphics/Data/Model/CModel2D.hpp" +namespace CosmicCore { + class CRenderer2D : public CAbstractRenderer{ + + CModel2D* m_model; + + public: + CRenderer2D() = delete; + CRenderer2D(CEntity& e): CAbstractRenderer(e){}; + CRenderer2D(CEntity& e, CModel2D* mod): CAbstractRenderer(e), m_model(mod){}; + nlohmann::json to_json() override{return nlohmann::json();}; + CModel2D* getModel(){return m_model;}; + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Component/Graphics/CTextRenderer.hpp b/src/Engine/Core/Component/Graphics/CTextRenderer.hpp new file mode 100644 index 0000000..c4e3c18 --- /dev/null +++ b/src/Engine/Core/Component/Graphics/CTextRenderer.hpp @@ -0,0 +1,27 @@ +#ifndef CTEXTRENDERER_HPP +#define CTEXTRENDERER_HPP + +#include "Core/Component/Graphics/CAbstractRenderer.hpp" +#include "Core/Entity/CEntity.hpp" +#include "Core/Systems/Graphics/Data/Font/CFont.hpp" +#include "Core/Systems/Graphics/Data/Model/CModel2D.hpp" +#include "nlohmann/json_fwd.hpp" +namespace CosmicCore { + //TODO pipeline vulkan dédié.... + class CTextRenderer : public CAbstractRenderer + { + private: + CModel2D* m_model; + std::string m_text; + public: + CTextRenderer(CEntity& entity): CAbstractRenderer(entity){}; + CTextRenderer(CEntity& e, CModel2D* mod): CAbstractRenderer(e), m_model(mod){}; + CTextRenderer(CEntity& e, CModel2D* mod, std::string text): CAbstractRenderer(e), m_model(mod), m_text(text){}; + CModel2D* getModel(){return m_model;}; + const std::string& getText() const{return m_text;}; + + nlohmann::json to_json(){ return nlohmann::json(); }; + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Component/Input/CInputManager.cpp b/src/Engine/Core/Component/Input/CInputManager.cpp index 5696a17..21b6fd8 100644 --- a/src/Engine/Core/Component/Input/CInputManager.cpp +++ b/src/Engine/Core/Component/Input/CInputManager.cpp @@ -18,9 +18,14 @@ namespace CosmicCore { m_onReleased.push_back({actionName, cb, 0, false}); } - void CInputManager::onMouseMove(std::function cb) + void CInputManager::addOnMouseMove(std::function cb) { - m_onMouseMove = cb; + m_onMouseMove.emplace_back(cb); + } + + void CInputManager::addOnGenericMouseLeftClick(std::function cb) + { + m_onMouseLeftClickReleased.emplace_back(GenericMouseClickAction(cb)); } // appelé par CInputWorld::updateWorld() @@ -61,7 +66,20 @@ namespace CosmicCore { } glm::vec2 mouseRel = inputWorld.getMouseRelative(); - if (m_onMouseMove && (mouseRel.x != 0 || mouseRel.y != 0)) - m_onMouseMove(entity, mouseRel); + if (!m_onMouseMove.empty() && (mouseRel.x != 0 || mouseRel.y != 0)) + { + for(auto& cbH : m_onMouseMove) + { + cbH.cb(entity, mouseRel); + } + } + //todo other click (onClick and right click) + if(!m_onMouseLeftClickReleased.empty() && inputWorld.isLeftMouseButtonJustReleased()) + { + for(auto& clickCB : m_onMouseLeftClickReleased) + { + clickCB.cb(entity); + } + } } } \ No newline at end of file diff --git a/src/Engine/Core/Component/Input/CInputManager.hpp b/src/Engine/Core/Component/Input/CInputManager.hpp index e92a7be..6d8da7d 100644 --- a/src/Engine/Core/Component/Input/CInputManager.hpp +++ b/src/Engine/Core/Component/Input/CInputManager.hpp @@ -6,6 +6,7 @@ #include "../../Systems/Input/CInputDispatcher.hpp" #include "glm/fwd.hpp" #include "nlohmann/json_fwd.hpp" +#include namespace CosmicCore { @@ -19,12 +20,24 @@ namespace CosmicCore { InputAction resolvedId = 0; bool resolved = false; }; + + struct GenericMouseClickAction{ + std::function cb; + }; + + struct MouseMovementAction{ + std::function cb; + }; + std::vector m_onHeld; std::vector m_onPressed; std::vector m_onReleased; - std::function m_onMouseMove; - + std::vector m_onMouseMove; + std::vector m_onMouseLeftClickPressed; + std::vector m_onMouseLeftClickReleased; + std::vector m_onMouseRightClickPressed; + std::vector m_onMouseRightClickReleased; bool m_enabled = true; public: @@ -33,8 +46,9 @@ namespace CosmicCore { void onPressed(const std::string& actionName, std::function cb); void onHeld(const std::string& actionName, std::function cb); - void onReleased(const std::string& actionNamen, std::function cb); - void onMouseMove(std::function cb); + void onReleased(const std::string& actionName, std::function cb); + void addOnMouseMove(std::function cb); + void addOnGenericMouseLeftClick(std::function cb); void setEnabled(bool enabled) { m_enabled = enabled; } diff --git a/src/Engine/Core/Entity/CEntity.hpp b/src/Engine/Core/Entity/CEntity.hpp index 6ccf1bf..559737b 100644 --- a/src/Engine/Core/Entity/CEntity.hpp +++ b/src/Engine/Core/Entity/CEntity.hpp @@ -47,9 +47,9 @@ namespace CosmicCore //CEntity getParent(); template - void addComponent(std::forward_list args) + void addComponent(Args&&... args) { - m_registryReference().emplace(m_handle, *this, args); + m_registryReference().emplace(m_handle, *this, std::forward(args)...); } template diff --git a/src/Engine/Core/Kernel/CKernel.hpp b/src/Engine/Core/Kernel/CKernel.hpp index 56523c3..dea3c25 100644 --- a/src/Engine/Core/Kernel/CKernel.hpp +++ b/src/Engine/Core/Kernel/CKernel.hpp @@ -1,9 +1,26 @@ #ifndef CKERNEL_HPP #define CKERNEL_HPP +#include "Core/Component/Camera/CCamera.hpp" +#include "Core/Component/Camera/CCamera2D.hpp" + +#include "Core/Component/Geometry/CTransform2D.hpp" +#include "Core/Component/Graphics/CRenderer2D.hpp" +#include "Core/Component/Graphics/CTextRenderer.hpp" +#include "Core/Systems/Graphics/Data/CModelLoader.hpp" +#include "Core/Systems/Graphics/Data/Material/CMaterial2D.hpp" +#include "Core/Systems/Graphics/Data/Mesh/CMesh2D.hpp" +#include "Core/Systems/Graphics/Data/Model/CModel2D.hpp" +#include "Core/Systems/Graphics/Shader/Implementations/CShaderImplVulkan.hpp" #include "Core/Systems/Input/CInputDispatcher.hpp" #include "../../Utils/Configurations/CBasicConfiguration.hpp" +#include "Core/Systems/Resources/API/CResourceAPI.hpp" +#include "Core/Systems/Resources/Font/CFontManager.hpp" +#include "Utils/Factory/ComponentFactory.hpp" +#include "glm/ext/vector_float4.hpp" +#include #include +#include #define GLM_ENABLE_EXPERIMENTAL #include #include @@ -62,7 +79,9 @@ namespace CosmicCore { virtual CScene* getActiveScene() = 0; virtual void quit() = 0; virtual void cleanup() = 0; - + virtual unsigned int getWindowHeight() = 0; + virtual unsigned int getWindowWidth() = 0; + virtual ~CKernelBase() = default; }; @@ -100,15 +119,17 @@ namespace CosmicCore { CKernel() = delete; - std::string getName() { return m_gameName; }; + std::string getName() override { return m_gameName; }; + unsigned int getWindowHeight() override {return m_window.getHeight();}; + unsigned int getWindowWidth() override {return m_window.getWidth();}; - void cleanup(){m_sceneMap.clear();}; + void cleanup() override {m_sceneMap.clear();}; - unsigned int getDeltatime(void) { + unsigned int getDeltatime(void) override { return m_deltaTime; } - void setDeltatime(unsigned int delta){ + void setDeltatime(unsigned int delta) override{ m_deltaTime = delta; } @@ -122,7 +143,7 @@ namespace CosmicCore { { } - CScene* getActiveScene() + CScene* getActiveScene() override { return m_activeScene; } @@ -131,10 +152,9 @@ namespace CosmicCore { loadConfigurations(); CContext::init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC); CScriptAPI::init(); - //CScriptRegister::registerAllScripts(); CPhysicsAPI::init(); - + std::filesystem::path pathToSchema("schema_json.json"); CosmicUtils::JsonValidator::init(pathToSchema); if(!isPreview) @@ -143,6 +163,31 @@ namespace CosmicCore { auto scene = CScene::load("scenes/scene1.json"); m_activeScene = scene.get(); m_sceneMap[scene->getName()] = std::move(scene); + auto font = CResourceAPI::resources().fonts().loadFont("assets/fonts/Arial"); + auto ent = m_activeScene->createEntity(); + ComponentFactory::Transform2DConfig trConf = { + {100.0,100.0}, + {75.0,75.0}, + {1.0,1.0}, + {0.0,0.0}, + 0.0, + 0.0, + true}; + ComponentFactory::addTransform2D(ent, trConf); + Model2DLoadConfig config; + config.shaderName = "ui"; + auto shader = CResourceAPI::resources().shaders().get(config.shaderName); + MeshMaterial2D mm2d; + mm2d.material = new CMaterial2D(); + mm2d.material->m_color = {1,1,1,1}; + mm2d.material->m_font = font; + mm2d.material->shader = static_cast(shader); + mm2d.material->build(); + mm2d.mesh = new CMesh2D(); + mm2d.mesh->buildFromText(mm2d.material->m_font, "TEST DE FONT"); + + CModel2D* model = new CModel2D({mm2d}); + ent.addComponent(model); } } @@ -241,7 +286,7 @@ namespace CosmicCore { CContext::quit(); } - void quit() { + void quit() override { m_finished = true; } diff --git a/src/Engine/Core/Scene/CScene.cpp b/src/Engine/Core/Scene/CScene.cpp index dcbc4e8..a4c7483 100644 --- a/src/Engine/Core/Scene/CScene.cpp +++ b/src/Engine/Core/Scene/CScene.cpp @@ -9,7 +9,13 @@ #include "../../Utils/Factory/CEntityFactory.hpp" #include "../../Utils/Factory/ComponentFactory.hpp" +#include "Core/Component/Camera/CCamera2D.hpp" +#include "Core/Component/Collider/CCollider2D.hpp" +#include "Core/Component/Geometry/CTransform2D.hpp" +#include "Core/Component/Graphics/CRenderer2D.hpp" +#include "Core/Component/Graphics/CTextRenderer.hpp" #include "Core/Component/Light/CLight.hpp" +#include "Core/Entity/EntityComponentManager.hpp" #include "glm/ext/vector_float3.hpp" #include "glm/gtc/type_ptr.hpp" #include "nlohmann/json_fwd.hpp" @@ -32,6 +38,11 @@ namespace CosmicCore { m_audioWorld.initWorld(); m_scriptWorld.initWorld(); m_lightsBuffer.init(); + //m_uiWorld.init(); + + m_ecManager.registry.sort([](const CTransform2D& lhs, const CTransform2D& rhs) { + return lhs.getZOrder() > rhs.getZOrder(); + }); } @@ -44,6 +55,8 @@ namespace CosmicCore { m_tangibleWorld.destroy(); m_audioWorld.destroy(); m_scriptWorld.destroy(); + m_lightsBuffer.destroy(); + //m_uiWorld.destroy(); } CEntity CScene::createEntity(){ @@ -92,66 +105,165 @@ namespace CosmicCore { m_lightsBuffer.update(frameIndex, lightsData); } - - void CScene::render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ + void CScene::render3D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ auto entities = m_ecManager.registry.view(); - VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); - auto cam = m_ecManager.registry.view(); - auto& camera = m_ecManager.registry.get(cam.front()); - auto& transform = m_ecManager.registry.get(cam.front()); - collectLights(cmd, frameIndex); - - camera.updateUniformBuffer(frameIndex, transform); - - cmd.bindDescriptorSets( - vk::PipelineBindPoint::eGraphics, - api->getDefaultPipelineLayout(), // layout du pipeline - 0, - *camera.getDescriptorSet(frameIndex), - {} - ); - - //bind lumières (set 3) - cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, - api->getDefaultPipelineLayout(), 3, - *m_lightsBuffer.getDescriptorSet(frameIndex), {}); - - - for (auto& entity : entities) { - auto model = m_ecManager.registry.get(entity).getModel(); - auto& transform = m_ecManager.registry.get(entity); - - transform.updateUniformBuffer(frameIndex); - //trier meshes par matérial ? - - // bind transform UBO (set = 1) + if(entities.begin() != entities.end()) + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + auto cam = m_ecManager.registry.view(); + auto& camera = m_ecManager.registry.get(cam.front()); + auto& transform = m_ecManager.registry.get(cam.front()); + + collectLights(cmd, frameIndex); + + camera.updateUniformBuffer(frameIndex, transform); + cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefaultPipelineLayout(), // layout du pipeline - 1, // set = 1 - *transform.getDescriptorSet(frameIndex), + 0, + *camera.getDescriptorSet(frameIndex), {} ); + + //bind lumières (set 3) + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + api->getDefaultPipelineLayout(), 3, + *m_lightsBuffer.getDescriptorSet(frameIndex), {}); + + + for (auto& entity : entities) { + auto model = m_ecManager.registry.get(entity).getModel(); + auto& transform = m_ecManager.registry.get(entity); + + transform.updateUniformBuffer(frameIndex); + //trier meshes par matérial ? + + // bind transform UBO (set = 1) + cmd.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + api->getDefaultPipelineLayout(), // layout du pipeline + 1, // set = 1 + *transform.getDescriptorSet(frameIndex), + {} + ); + + for (auto& mm : model->getMeshMaterials()) { + // ne rebind le pipeline que si le material change + //if (mesh.getMaterial() != boundMaterial) { + //boundMaterial = mesh.getMaterial(); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipeline()); + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipelineLayout(), + 2, + *mm.material->getDescriptorSet(frameIndex), + {}); + //} + + cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); + cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); + cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); + } + } + } + } - for (auto& mm : model->getMeshMaterials()) { - // ne rebind le pipeline que si le material change - //if (mesh.getMaterial() != boundMaterial) { - //boundMaterial = mesh.getMaterial(); - cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, - *mm.material->getPipeline()); - cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, - *mm.material->getPipelineLayout(), - 2, - *mm.material->getDescriptorSet(frameIndex), - {}); - //} - - cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); - cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); - cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); - } - } + void CScene::render2D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ + auto entities = m_ecManager.registry.view(); + auto textEntities = m_ecManager.registry.view(); + + if(entities.begin() != entities.end()) + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + auto cam = m_ecManager.registry.view(); + auto& camera = m_ecManager.registry.get(cam.front()); + auto& trCam = m_ecManager.registry.get(cam.front()); + + camera.updateUniformBuffer(frameIndex, trCam); + // + cmd.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + api->getDefault2DPipelineLayout(), // layout du pipeline + 2, + *camera.getDescriptorSet(frameIndex), + {} + ); + + for (auto& entity : entities) { + auto model = m_ecManager.registry.get(entity).getModel(); + auto& transform = m_ecManager.registry.get(entity); + + transform.updateUniformBuffer(frameIndex); + + // bind transform UBO (set = 1) + cmd.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + api->getDefault2DPipelineLayout(), // layout du pipeline + 0, // set = 1 + *transform.getDescriptorSet(frameIndex), + {} + ); + + for (auto& mm : model->getMeshMaterials()) { + // ne rebind le pipeline que si le material change + //if (mesh.getMaterial() != boundMaterial) { + //boundMaterial = mesh.getMaterial(); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipeline()); + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipelineLayout(), + 1, + *mm.material->getDescriptorSet(frameIndex), + {}); + //} + + cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); + cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); + cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); + } + } + + for (auto& entity : textEntities) { + auto& textRenderer = m_ecManager.registry.get(entity); + auto& transform = m_ecManager.registry.get(entity); + auto model = textRenderer.getModel(); + transform.updateUniformBuffer(frameIndex); + + // bind transform UBO (set = 1) + cmd.bindDescriptorSets( + vk::PipelineBindPoint::eGraphics, + api->getDefault2DPipelineLayout(), // layout du pipeline + 0, // set = 1 + *transform.getDescriptorSet(frameIndex), + {} + ); + + for (auto& mm : model->getMeshMaterials()) { + // ne rebind le pipeline que si le material change + //if (mesh.getMaterial() != boundMaterial) { + //boundMaterial = mesh.getMaterial(); + cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipeline()); + cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + *mm.material->getPipelineLayout(), + 1, + *mm.material->getDescriptorSet(frameIndex), + {}); + //} + cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); + cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); + cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); + } + } + + } + } + + void CScene::render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ + render3D(cmd, frameIndex); + render2D(cmd, frameIndex); } nlohmann::json CScene::to_json() @@ -285,6 +397,59 @@ namespace CosmicCore { } } + nlohmann::json& entities2D = sceneJson[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Scene_Entities2D)]; + for(auto& entity : entities2D.items()) + { + nlohmann::json& entityObj = entity.value(); + auto ref = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Ref)].get(); + + nlohmann::json& components = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Components)]; + nlohmann::json& transform = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Transform2D)]; + nlohmann::json& camera = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Camera2D)]; + nlohmann::json& collider = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Collider2D)]; + nlohmann::json& renderer = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Renderer2D)]; + nlohmann::json& script = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Script)]; + + auto trConfig(!transform.is_null() ? std::optional({ + glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Position2D)].get>().data()), + glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Size2D)].get>().data()), + glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Scale2D)].get>().data()), + glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Pivot2D)].get>().data()), + transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Rotation2D)].get(), + transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_zOrder2D)].get(), + transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Visible2D)].get() + }) : std::nullopt); + + auto camConfig(!camera.is_null() ? std::optional({ + camera[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Camera_Zoom2D)].get() + }) : std::nullopt); + + auto colliderConfig(!collider.is_null() ? std::optional({ + static_cast(collider[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Collider_Shape2D)].get()) + }) : std::nullopt); + + auto rendererConfig(!renderer.is_null() ? std::optional({ + renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Model2D)].get(), + renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Shader2D)].get(), + }) : std::nullopt); + + auto scriptConfig(!script.is_null() ? std::optional({ + script.get>() + }): std::nullopt); + + CosmicUtils::CEntityFactory::Entity2DConfig config = { + entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Name)], + entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Description)], + trConfig, + camConfig, + rendererConfig, + colliderConfig, + scriptConfig + }; + + auto entityHandle = CosmicUtils::CEntityFactory::create(scene.get(), config); + } + //Connect entities to relationships for(auto& [entityNb, handle]: idToHandle) { diff --git a/src/Engine/Core/Scene/CScene.hpp b/src/Engine/Core/Scene/CScene.hpp index 3353530..8b8496c 100644 --- a/src/Engine/Core/Scene/CScene.hpp +++ b/src/Engine/Core/Scene/CScene.hpp @@ -9,6 +9,7 @@ #include "../Systems/Audio/CAudioWorld.hpp" #include "../Systems/Scripts/CScriptWorld.hpp" #include "Core/Systems/Graphics/Data/Light/CLightsBuffer.hpp" +#include "Core/Systems/Graphics/UserInterface/CUIWorld.hpp" namespace CosmicCore { class CEntity; @@ -21,6 +22,11 @@ namespace CosmicCore { CAudioWorld m_audioWorld; CScriptWorld m_scriptWorld; CLightsBuffer m_lightsBuffer; + //CUIWorld m_uiWorld; + + void render3D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex); + void render2D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex); + public: CScene() = delete; CScene(std::string name); @@ -47,6 +53,7 @@ namespace CosmicCore { CScriptWorld& getScriptWorld() {return m_scriptWorld;}; + //CUIWorld& getUIWorld() {return m_uiWorld;}; //CEntity* getActiveCamera(); //void setActiveCamera(CEntity* newCamera); @@ -87,6 +94,7 @@ namespace CosmicCore { //unsigned int getMask(); void render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex); + void collectLights(vk::raii::CommandBuffer& cmd, uint32_t frameIndex); //void updateScript(); diff --git a/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.cpp b/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.cpp index c708c40..823ffa6 100644 --- a/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.cpp +++ b/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.cpp @@ -101,11 +101,16 @@ void VulkanImpl::cleanup(){ // descriptor set layouts + pipeline layout avant le device defaultPipelineLayoutInfo = nullptr; + default2DPipelineLayoutInfo = nullptr; cameraLayout = nullptr; transformLayout = nullptr; materialLayout = nullptr; lightLayout = nullptr; - + + projection2DLayout = nullptr; + transform2DLayout = nullptr; + material2DLayout = nullptr; + VmaTotalStatistics stats; vmaCalculateStatistics(allocator, &stats); if (stats.total.statistics.allocationCount > 0) { @@ -646,6 +651,57 @@ void VulkanImpl::createDescriptorSetLayouts() layouts.data() }; defaultPipelineLayoutInfo = vk::raii::PipelineLayout(device, layoutInfo); + + //Create 2D dfault pipeline + + // set 0 - Transform : un UBO en vertex shader + vk::DescriptorSetLayoutBinding transform2DBinding{ + 0, + vk::DescriptorType::eUniformBuffer, + 1, + vk::ShaderStageFlagBits::eVertex, + nullptr + }; + transform2DLayout = vk::raii::DescriptorSetLayout( + device, + vk::DescriptorSetLayoutCreateInfo{{}, 1, &transform2DBinding} + ); + + // set 2 - Material : un UBO + deux samplers en fragment shader + std::array material2DBindings{{ + {0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eFragment, nullptr}, + {1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment, nullptr} + }}; + material2DLayout = vk::raii::DescriptorSetLayout( + device, + vk::DescriptorSetLayoutCreateInfo{{}, + static_cast(material2DBindings.size()), + material2DBindings.data()} + ); + + // set 2 - Projection : un UBO en vertex shader + vk::DescriptorSetLayoutBinding projBinding{ + 0, // binding + vk::DescriptorType::eUniformBuffer, // type + 1, // count + vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, // stage + nullptr + }; + projection2DLayout = vk::raii::DescriptorSetLayout( + device, + vk::DescriptorSetLayoutCreateInfo{{}, 1, &projBinding} + ); + + std::array layouts2D{ + *transform2DLayout, + *material2DLayout, + *projection2DLayout + }; + vk::PipelineLayoutCreateInfo layout2DInfo{{}, + static_cast(layouts2D.size()), + layouts2D.data() + }; + default2DPipelineLayoutInfo = vk::raii::PipelineLayout(device, layout2DInfo); } //Fonction d'ajout de descriptor set qui regarde la taille de la pool, si la pool est dépassée, on ajoute une pool 2x plus grande diff --git a/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp b/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp index 53e2898..2562450 100644 --- a/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp +++ b/src/Engine/Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp @@ -139,8 +139,14 @@ class VulkanImpl: public GraphicsAPI{ vk::raii::DescriptorSetLayout materialLayout = nullptr; // set 2 vk::raii::DescriptorSetLayout lightLayout = nullptr; // set 3 + vk::raii::DescriptorSetLayout transform2DLayout = nullptr; // set 0 + vk::raii::DescriptorSetLayout material2DLayout = nullptr; // set 1 + vk::raii::DescriptorSetLayout projection2DLayout = nullptr; // set 2 + + DescriptorAllocator descriptorPoolManager; vk::raii::PipelineLayout defaultPipelineLayoutInfo = nullptr; + vk::raii::PipelineLayout default2DPipelineLayoutInfo = nullptr; vk::raii::Image depthImage = nullptr; vk::raii::DeviceMemory depthImageMemory = nullptr; @@ -198,6 +204,10 @@ class VulkanImpl: public GraphicsAPI{ vk::raii::DescriptorSetLayout& getMaterialLayout() { return materialLayout; } vk::raii::DescriptorSetLayout& getLightLayout() { return lightLayout; } + vk::raii::DescriptorSetLayout& getTransform2DLayout() { return transform2DLayout; } + vk::raii::DescriptorSetLayout& getMaterial2DLayout() { return material2DLayout; } + vk::raii::DescriptorSetLayout& getProjection2DLayout() { return projection2DLayout; } + vk::raii::ImageView createImageView(vk::raii::Image& image, vk::Format format, vk::ImageAspectFlags aspectFlags); void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size); @@ -211,6 +221,7 @@ class VulkanImpl: public GraphicsAPI{ DescriptorAllocator& getDescriptorPoolManager(){return descriptorPoolManager;}; vk::raii::PipelineLayout& getDefaultPipelineLayout(){return defaultPipelineLayoutInfo;}; + vk::raii::PipelineLayout& getDefault2DPipelineLayout(){return default2DPipelineLayoutInfo;}; void copyBufferToImage(const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height); diff --git a/src/Engine/Core/Systems/Graphics/Data/CModelLoader.cpp b/src/Engine/Core/Systems/Graphics/Data/CModelLoader.cpp index a16e8a5..f3615e5 100644 --- a/src/Engine/Core/Systems/Graphics/Data/CModelLoader.cpp +++ b/src/Engine/Core/Systems/Graphics/Data/CModelLoader.cpp @@ -1,7 +1,12 @@ #include "CModelLoader.hpp" +#include #include "../API/GraphicsAPI.hpp" #include "../../Resources/API/CResourceAPI.hpp" +#include "Core/Systems/Graphics/Data/Material/CMaterial2D.hpp" +#include "Core/Systems/Graphics/Data/Model/CModel2D.hpp" +#include "nlohmann/json_fwd.hpp" #include +#include CModel* CModelLoader::loadModel(std::string fileName, const ModelLoadConfig& config) { @@ -189,4 +194,144 @@ CMaterial* CModelLoader::processMaterial(aiMaterial* mat, const std::string& dir rm.getTextureManager().addTexture(directory, std::move(tex)); return ptr; } -}*/ \ No newline at end of file +}*/ + +CosmicCore::CModel2D* CModelLoader::loadModel2D(std::string filename, const Model2DLoadConfig& config) +{ + auto& rm = CResourceAPI::resources(); + + // Check cache first + auto cached = rm.models2D().get(filename); + if (cached) { + return cached.value(); + } + + // Load and parse JSON file + std::ifstream file(filename); + if (!file.is_open()) { + throw std::runtime_error("Failed to open 2D model file: " + filename); + } + nlohmann::json jsonData = nlohmann::json::parse(file); + + std::vector meshMaterials; + for(auto& mesh : jsonData["meshes"]) + { + loadMesh2D(mesh, filename, meshMaterials, config); + } + + + // Create and register model2D + auto model2D = std::make_unique(meshMaterials); + return rm.models2D().add(filename, std::move(model2D)); +} + +void CModelLoader::loadMesh2D(nlohmann::json& mesh, std::string filename, std::vector& meshes, const Model2DLoadConfig& config) +{ + auto& rm = CResourceAPI::resources(); + + // Parse vertices + std::vector vertices; + if (mesh.contains("vertices") && mesh["vertices"].is_array()) { + for (const auto& v : mesh["vertices"]) { + Vertex2D vertex; + + // Position (required: x, y) + vertex.m_position = glm::vec2(v["x"], v["y"]); + + // TexCoords (optional, defaults to 0,0) + if (v.contains("u") && v.contains("v")) { + vertex.m_uv = glm::vec2(v["u"], v["v"]); + } else { + vertex.m_uv = glm::vec2(0.0f); + } + + // Color (optional, defaults to white) + if (v.contains("r") && v.contains("g") && v.contains("b") && v.contains("a")) { + vertex.m_color = glm::vec4(v["r"], v["g"], v["b"], v["a"]); + } else { + vertex.m_color = glm::vec4(1.0f); + } + + vertices.push_back(vertex); + } + } + + // Parse indices + std::vector indices; + if (mesh.contains("indices") && mesh["indices"].is_array()) { + for (const auto& i : mesh["indices"]) { + indices.push_back(i.get()); + } + } + + if (vertices.empty() || indices.empty()) { + throw std::runtime_error("Invalid 2D model file: missing vertices or indices in " + filename); + } + + + // Create mesh key + std::string meshKey = filename + "_" + std::to_string(meshes.size()) + "_mesh2d"; + + // Create and setup CMesh2D + auto mesh2D = std::make_unique(); + mesh2D->setVertices(vertices); + mesh2D->setIndexes(indices); + mesh2D->load(); + + CMesh2D* meshPtr = rm.meshes2D().add(meshKey, std::move(mesh2D)); + CMaterial2D* matPtr = loadMaterial2D(mesh["material"], filename, config); + meshes.push_back({meshPtr, matPtr}); +} + +CosmicCore::CMaterial2D* CModelLoader::loadMaterial2D(nlohmann::json& material, std::string filename, const Model2DLoadConfig& config) +{ + auto& rm = CResourceAPI::resources(); + + // Create material2D + CMaterial2D* material2D = nullptr; + + + std::string matKey = filename + "_mat2d"; + auto cachedMat = rm.materials2D().get(matKey); + + if (!cachedMat) { + auto mat = std::make_unique(); + + // Parse material from JSON + if (material.contains("material")) { + auto& matJson = material["material"]; + + if (matJson.contains("color")) { + auto& color = matJson["color"]; + mat->m_color = glm::vec4( + color.value("r", 1.0f), + color.value("g", 1.0f), + color.value("b", 1.0f), + color.value("a", 1.0f) + ); + } + + if (matJson.contains("alpha_blend")) { + mat->m_alphaBlend = matJson["alpha_blend"].get(); + } + + if (matJson.contains("texture")) { + std::string texPath = matJson["texture"]; + mat->m_texture = rm.textures().loadTexture(texPath); + } + } + + // Get shader from config + auto shader = rm.shaders().get(config.shaderName); + if (!shader) { + throw std::runtime_error("Shader not found: " + config.shaderName); + } + mat->shader = static_cast(shader); + mat->build(); + + material2D = rm.materials2D().add(matKey, std::move(mat)); + } else { + material2D = cachedMat.value(); + } + return material2D; +} \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/CModelLoader.hpp b/src/Engine/Core/Systems/Graphics/Data/CModelLoader.hpp index 93b4195..1787284 100644 --- a/src/Engine/Core/Systems/Graphics/Data/CModelLoader.hpp +++ b/src/Engine/Core/Systems/Graphics/Data/CModelLoader.hpp @@ -6,8 +6,11 @@ #include #include +#include "Core/Systems/Graphics/Data/Material/CMaterial2D.hpp" +#include "Core/Systems/Graphics/Data/Model/CModel2D.hpp" #include "Model/CModel.hpp" #include "Texture/CTexture.hpp" +#include "nlohmann/json_fwd.hpp" struct ModelLoadConfig { std::string shaderName = "triangle"; @@ -17,6 +20,14 @@ struct ModelLoadConfig { bool forceReload = false; }; +struct Model2DLoadConfig { + std::string shaderName = "ui"; + // override des materials par index de mesh + //std::unordered_map materialOverrides; + // si true, recharge même si déjà en cache + //bool forceReload = false; +}; + /** * @brief Class allowing to load models from obj files. */ @@ -51,6 +62,10 @@ private: static CMaterial* processMaterial(aiMaterial* mat, const std::string& directory, const ModelLoadConfig& config); static CModel* cloneWithOverrides(CModel* original, const std::string& originalKey, const ModelLoadConfig& config); + + static void loadMesh2D(nlohmann::json& mesh, std::string filename, std::vector& meshes, const Model2DLoadConfig& config = {}); + static CosmicCore::CMaterial2D* loadMaterial2D(nlohmann::json& material, std::string filename, const Model2DLoadConfig& config = {}); + public: /** @@ -60,6 +75,7 @@ public: * @return A dynamically allocated CModel. */ static CModel* loadModel(std::string filename, const ModelLoadConfig& config = {}); + static CosmicCore::CModel2D* loadModel2D(std::string filename, const Model2DLoadConfig& config = {}); }; diff --git a/src/Engine/Core/Systems/Graphics/Data/Font/CFont.cpp b/src/Engine/Core/Systems/Graphics/Data/Font/CFont.cpp new file mode 100644 index 0000000..e105468 --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Font/CFont.cpp @@ -0,0 +1,76 @@ +// CFont.cpp +#include "CFont.hpp" +#include "Core/Systems/Resources/API/CResourceAPI.hpp" +#include +#include +#include + +namespace CosmicCore { + +void CFont::init(const std::string& jsonPath, const std::string& atlasPath) { + // charge l'atlas comme texture + auto& rm = CResourceAPI::resources().textures(); + m_atlas = rm.loadTexture(atlasPath); + + // parse le JSON + std::ifstream file(jsonPath); + if (!file.good()) + throw std::runtime_error("Font JSON not found: " + jsonPath); + + nlohmann::json j = nlohmann::json::parse(file); + + // métriques globales + if (j.contains("metrics")) { + auto& m = j["metrics"]; + m_metrics.emSize = m.value("emSize", 1.0f); + m_metrics.lineHeight = m.value("lineHeight", 1.0f); + m_metrics.ascender = m.value("ascender", 1.0f); + m_metrics.descender = m.value("descender", 0.0f); + } + + // dimensions de l'atlas + if (j.contains("atlas")) { + m_atlasWidth = j["atlas"].value("width", 512u); + m_atlasHeight = j["atlas"].value("height", 512u); + } + + // glyphes + if (!j.contains("glyphs")) return; + + for (auto& g : j["glyphs"]) { + SGlyph glyph{}; + glyph.unicode = g.value("unicode", 0u); + glyph.advance = g.value("advance", 0.0f); + + if (g.contains("atlasBounds")) { + auto& ab = g["atlasBounds"]; + float atlasW = (float)m_atlasWidth; + float atlasH = (float)m_atlasHeight; + glyph.atlasMin = {ab["left"].get() / atlasW, + ab["bottom"].get() / atlasH}; + glyph.atlasMax = {ab["right"].get() / atlasW, + ab["top"].get() / atlasH}; + } + + if (g.contains("planeBounds")) { + auto& pb = g["planeBounds"]; + glyph.planeMin = {pb["left"].get(), + pb["bottom"].get()}; + glyph.planeMax = {pb["right"].get(), + pb["top"].get()}; + } + + m_glyphs[glyph.unicode] = glyph; + } +} + +const SGlyph* CFont::getGlyph(uint32_t unicode) const { + auto it = m_glyphs.find(unicode); + if (it != m_glyphs.end()) return &it->second; + // fallback sur '?' si le glyphe n'existe pas + auto fallback = m_glyphs.find('?'); + if (fallback != m_glyphs.end()) return &fallback->second; + return nullptr; +} + +} // namespace CosmicCore \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Font/CFont.hpp b/src/Engine/Core/Systems/Graphics/Data/Font/CFont.hpp new file mode 100644 index 0000000..b5d85e8 --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Font/CFont.hpp @@ -0,0 +1,57 @@ +#ifndef CFONT_HPP +#define CFONT_HPP + +#include +#include +#include +#include "../Texture/CTexture.hpp" + +namespace CosmicCore { + +struct SGlyph { + uint32_t unicode; + float advance; // largeur pour avancer le curseur + + // position dans l'atlas (UV) + glm::vec2 atlasMin; // UV coin bas-gauche + glm::vec2 atlasMax; // UV coin haut-droit + + // position relative au curseur (plane bounds) + glm::vec2 planeMin; // offset bas-gauche + glm::vec2 planeMax; // offset haut-droit +}; + +struct SFontMetrics { + float emSize = 1.0f; + float lineHeight = 1.0f; + float ascender = 1.0f; + float descender = 0.0f; +}; + +class CFont { + std::unordered_map m_glyphs; + CTexture* m_atlas; + SFontMetrics m_metrics; + uint32_t m_atlasWidth = 0; + uint32_t m_atlasHeight = 0; + + public: + CFont() = default; + ~CFont() = default; + + CFont(const CFont&) = delete; + CFont& operator=(const CFont&) = delete; + CFont(CFont&&) = default; + CFont& operator=(CFont&&) = default; + + void init(const std::string& jsonPath, const std::string& atlasPath); + + const SGlyph* getGlyph(uint32_t unicode) const; + CTexture* getAtlas() const { return m_atlas; } + SFontMetrics getMetrics() const { return m_metrics; } + uint32_t getAtlasWidth() const { return m_atlasWidth; } + uint32_t getAtlasHeight() const { return m_atlasHeight; } +}; + +} // namespace CosmicCore +#endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.cpp b/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.cpp deleted file mode 100644 index ea11151..0000000 --- a/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/*#include "CTextTexture.hpp" - -CTextTexture::CTextTexture(ETextureType type, std::string filePath, std::string text, unsigned int fontSize, glm::vec3 fontColor, glm::bvec4 fontStyle) : - CAbstractTexture(type), - m_fontFilePath(filePath), - m_renderText(text), - m_fontSize(fontSize), - m_fontColor(fontColor), - m_fontStyle(fontStyle) { -} - -std::string CTextTexture::getFontFilePath(void) { - return m_fontFilePath; -} - -void CTextTexture::setFontFilePath(std::string filePath) { - m_fontFilePath = filePath; -} - -std::string CTextTexture::getText(void) { - return m_renderText; -} - -void CTextTexture::setText(std::string text) { - m_renderText = text; -} - -void CTextTexture::init(void) { - // Read the font file. - TTF_Font* font = TTF_OpenFont(m_fontFilePath.c_str(), m_fontSize); - - SDL_Color color; - color.r = m_fontColor.x / 255u; - color.g = m_fontColor.y / 255u; - color.b = m_fontColor.z / 255u; - - int style = TTF_STYLE_NORMAL; - if (m_fontStyle.x) { - style |= TTF_STYLE_BOLD; - } - if (m_fontStyle.y) { - style |= TTF_STYLE_ITALIC; - } - if (m_fontStyle.z) { - style |= TTF_STYLE_UNDERLINE; - } - if (m_fontStyle.z) { - style |= TTF_STYLE_STRIKETHROUGH; - } - TTF_SetFontStyle(font, style); - - SDL_Surface* sdlSurface = TTF_RenderText_Blended(font, m_renderText.c_str(), color); - - if (sdlSurface == NULL) { - throw CLibException(std::string("Can not render the text : ") + std::string(SDL_GetError())); - } - - // Create the id. - unsigned int id; - glGenTextures(1, &id); - setId(id); - - // Image format. - GLenum internalFormat(0); - GLenum externalFormat(0); - - if (sdlSurface->format->BytesPerPixel == 3) { - // We use RGB as internal format. - internalFormat = GL_RGB; - - // Choose the external format. - if (sdlSurface->format->Rmask == 0xff) - externalFormat = GL_RGB; - else - externalFormat = GL_BGR; - } - else if (sdlSurface->format->BytesPerPixel == 4) { - // We use RGBA as internal format. - internalFormat = GL_RGBA; - - // Choose the external format. - if (sdlSurface->format->Rmask == 0xff) - externalFormat = GL_RGBA; - else - externalFormat = GL_BGRA; - } - else { - SDL_FreeSurface(sdlSurface); - throw CRuntimeException("Unknow image internal format."); - } - - // Lock the texture to use it. - glBindTexture(GL_TEXTURE_2D, getId()); - - // Fill the GL texture. - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, sdlSurface->w, sdlSurface->h, 0, externalFormat, GL_UNSIGNED_BYTE, sdlSurface->pixels); - - // Set filters : the near texture have a linear filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // The far texture have a nearest filter, meaning no filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // Unlock the texture. - glBindTexture(GL_TEXTURE_2D, 0); - - // Free the font. - TTF_CloseFont(font); - - // Free the surface. - SDL_FreeSurface(sdlSurface); -}*/ \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.hpp b/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.hpp deleted file mode 100644 index 26b9b40..0000000 --- a/src/Engine/Core/Systems/Graphics/Data/Font/CTextTexture.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/*#ifndef CTEXTTEXTURE_HPP -#define CTEXTTEXTURE_HPP - -#include "../../../Controller/Exception/CLibException.hpp" -#include "../../../Controller/Exception/CRuntimeException.hpp" -#include "../../../Controller/Exception/CLogicException.hpp" -#include "CAbstractTexture.hpp" - -#include -#include -#include -#include -#ifdef WIN32 - #include -#else - #include -#endif - -class CTextTexture : CAbstractTexture { -private: - // Path of the file. - std::string m_fontFilePath; - - // The size of the font. - unsigned int m_fontSize; - - // The color of the font. - glm::vec3 m_fontColor; - - // The style of the font (x is bold, y is italic, z is underline, w is strikethrough). - glm::bvec4 m_fontStyle; - - // The text to render. - std::string m_renderText; - -public: - CTextTexture(void) = delete; - CTextTexture(ETextureType type, std::string filePath, std::string text, unsigned int fontSize, glm::vec3 fontColor, glm::bvec4 fontStyle); - ~CTextTexture() {}; - std::string getFontFilePath(void); - void setFontFilePath(std::string filePath); - std::string getText(void); - void setText(std::string text); - virtual void init(void); -}; - -#endif*/ \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Light/CLightsBuffer.hpp b/src/Engine/Core/Systems/Graphics/Data/Light/CLightsBuffer.hpp index 3bfb192..93cb016 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Light/CLightsBuffer.hpp +++ b/src/Engine/Core/Systems/Graphics/Data/Light/CLightsBuffer.hpp @@ -35,7 +35,7 @@ class CLightsBuffer { public: CLightsBuffer() = default; - ~CLightsBuffer() { destroy(); } + ~CLightsBuffer() { }//destroy(); } CLightsBuffer(const CLightsBuffer&) = delete; CLightsBuffer& operator=(const CLightsBuffer&) = delete; diff --git a/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.cpp b/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.cpp new file mode 100644 index 0000000..fb30d6e --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.cpp @@ -0,0 +1,149 @@ +#include "CMaterial2D.hpp" +#include "../../../Resources/API/CResourceAPI.hpp" +#include "../../Shader/Implementations/CShaderImplVulkan.hpp" +#include "Core/Systems/Graphics/API/VulkanImplementation/VulkanImpl.hpp" +#include + +namespace CosmicCore { + +void CMaterial2D::build() { + + if(isInit) + { + destroy(); + } + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + auto* device= static_cast(api->getDevice()); + auto shaderStages = shader->getShaderStages(0, vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment); + + auto bindingDescription = Vertex2D::getBindingDescription(); + auto attributeDescriptions = Vertex2D::getAttributeDescriptions(); + vk::PipelineVertexInputStateCreateInfo vertexInputInfo{{}, 1, &bindingDescription, static_cast(attributeDescriptions.size()), attributeDescriptions.data()}; + + vk::PipelineInputAssemblyStateCreateInfo inputAssembly{{},vk::PrimitiveTopology::eTriangleList}; + vk::PipelineViewportStateCreateInfo viewportState{{},1, {},1}; + + vk::PipelineRasterizationStateCreateInfo rasterizer{{},vk::False, vk::False, vk::PolygonMode::eFill,vk::CullModeFlagBits::eBack, vk::FrontFace::eCounterClockwise, vk::False, {}, {}, 1.0f, 1.0f}; + + vk::PipelineMultisampleStateCreateInfo multisampling{{}, vk::SampleCountFlagBits::e1, vk::False}; + + vk::PipelineColorBlendAttachmentState colorBlendAttachment{vk::False, {}, {}, {}, {}, {}, {}, vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA}; + + vk::PipelineColorBlendStateCreateInfo colorBlending{{},vk::False, vk::LogicOp::eCopy, 1, &colorBlendAttachment}; + + vk::PipelineDepthStencilStateCreateInfo depthStencil{{}, + vk::True, + vk::True, + vk::CompareOp::eLess, + vk::False, + vk::False}; + + std::vector dynamicStates = { + vk::DynamicState::eViewport, + vk::DynamicState::eScissor}; + vk::PipelineDynamicStateCreateInfo dynamicState{{}, static_cast(dynamicStates.size()), dynamicStates.data()}; + + std::array layouts{ + *api->getTransform2DLayout(), // set 0 + *api->getMaterial2DLayout(), // set 1 + *api->getProjection2DLayout(), // set 2 + + }; + + vk::PipelineLayoutCreateInfo pipelineLayoutInfo{{},3,layouts.data(), 0}; + + pipelineLayout = vk::raii::PipelineLayout(*static_cast(api->getDevice()), pipelineLayoutInfo); + + vk::StructureChain pipelineCreateInfoChain = { + {{}, + 2, + shaderStages.data(), + &vertexInputInfo, + &inputAssembly, + {}, + &viewportState, + &rasterizer, + &multisampling, + &depthStencil, + &colorBlending, + &dynamicState, + pipelineLayout, + nullptr + }, + {{}, + 1, + &api->getSwapChainFormat().format, + api->findDepthFormat() + } + }; + + pipeline = vk::raii::Pipeline(*static_cast(api->getDevice()), nullptr, pipelineCreateInfoChain.get()); + + // descriptor sets du material (set 2) + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + m_descriptorSets[i] = api->getDescriptorPoolManager().allocate( + *api->getMaterial2DLayout() + ); + + std::vector writes; + + // binding 1 : albedo (si présent) + vk::DescriptorImageInfo albedoInfo; + if (m_texture) { + albedoInfo = { + *m_texture->getSampler(), + *m_texture->getImageView(), + vk::ImageLayout::eShaderReadOnlyOptimal + }; + writes.push_back({ + *m_descriptorSets[i].set, + 1, 0, 1, + vk::DescriptorType::eCombinedImageSampler, + &albedoInfo + }); + } + else if (m_font) { + albedoInfo = { + *m_font->getAtlas()->getSampler(), + *m_font->getAtlas()->getImageView(), + vk::ImageLayout::eShaderReadOnlyOptimal + }; + writes.push_back({ + *m_descriptorSets[i].set, + 1, 0, 1, + vk::DescriptorType::eCombinedImageSampler, + &albedoInfo + }); + } + else { + albedoInfo = { + api->getDefaultTexture()->getSampler(), + api->getDefaultTexture()->getImageView(), + vk::ImageLayout::eShaderReadOnlyOptimal + }; + writes.push_back({ + *m_descriptorSets[i].set, + 1, 0, 1, + vk::DescriptorType::eCombinedImageSampler, + &albedoInfo + }); + } + + if (!writes.empty()) + device->updateDescriptorSets(writes, {}); + } + isInit = true; +} + +void CMaterial2D::destroy() { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + api->destroyPipeline(pipeline, pipelineLayout); + + // descriptor sets + for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + api->destroyDescriptorSet(m_descriptorSets[i], i); + } +} + +} // namespace CosmicCore \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.hpp b/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.hpp new file mode 100644 index 0000000..c1b9f62 --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Material/CMaterial2D.hpp @@ -0,0 +1,48 @@ +#ifndef CUIPIPELINE_HPP +#define CUIPIPELINE_HPP + +#include "Core/Systems/Graphics/API/VulkanImplementation/Constants.hpp" +#include "Core/Systems/Graphics/API/VulkanImplementation/ManagedDescriptorSet.hpp" +#include "Core/Systems/Graphics/Data/Font/CFont.hpp" +#include "Core/Systems/Graphics/Data/Texture/CTexture.hpp" +#include "Core/Systems/Graphics/Shader/Implementations/CShaderImplVulkan.hpp" +#include + +namespace CosmicCore { + + class CMaterial2D { + private: + + + public: + glm::vec4 m_color = {1, 1, 1, 1}; + CTexture* m_texture = nullptr; + CFont* m_font = nullptr; + bool m_alphaBlend = true; + + bool isInit = false; + CTexture* texture = nullptr; + CShaderImplVulkan* shader; + vk::raii::PipelineLayout pipelineLayout = nullptr; + vk::raii::Pipeline pipeline = nullptr; + std::array m_descriptorSets; + void build(); + void destroy(); + + vk::raii::Pipeline& getPipeline() { return pipeline; } + vk::raii::PipelineLayout& getPipelineLayout() { return pipelineLayout; } + vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) { + return m_descriptorSets[frameIndex].set; + } + + CMaterial2D() = default; + ~CMaterial2D() { destroy(); } + + CMaterial2D(CMaterial2D&&) = default; + CMaterial2D& operator=(CMaterial2D&&) = default; + CMaterial2D(const CMaterial2D&) = delete; + CMaterial2D& operator=(const CMaterial2D&) = delete; + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.cpp b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.cpp index 4d8faad..1c5652d 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.cpp +++ b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.cpp @@ -14,8 +14,6 @@ void CMesh::destroy() { VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); api->destroyBuffer(vertexIndexBuffer, api->getCurrentFrameIndex()); - /*if (api && vertexIndexBuffer.buffer != VK_NULL_HANDLE) - vmaDestroyBuffer(api->getAllocator(), vertexIndexBuffer.buffer, vertexIndexBuffer.allocation);*/ } std::vector& CMesh::getVertices(void) { return m_vertexes; @@ -34,22 +32,6 @@ std::vector& CMesh::getIndexes(void){ return m_indexes; } -/*void CMesh::load(void) { - vk::BufferCreateInfo bufferInfo{{},sizeof(m_vertexes[0]) * m_vertexes.size(), vk::BufferUsageFlagBits::eVertexBuffer, vk::SharingMode::eExclusive}; - VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); - vertexBuffer = vk::raii::Buffer(*static_cast(api->getDevice()), bufferInfo); - - vk::MemoryRequirements memRequirements = vertexBuffer.getMemoryRequirements(); - vk::MemoryAllocateInfo memoryAllocateInfo{memRequirements.size, api->findMemoryType(memRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)}; - vertexBufferMemory = vk::raii::DeviceMemory(*static_cast(api->getDevice()), memoryAllocateInfo); - - vertexBuffer.bindMemory(*vertexBufferMemory, 0); - - void *data = vertexBufferMemory.mapMemory(0, bufferInfo.size); - memcpy(data, m_vertexes.data(), bufferInfo.size); - vertexBufferMemory.unmapMemory(); -}*/ - void CMesh::load(void) { VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); VmaAllocator allocator = api->getAllocator(); @@ -100,8 +82,4 @@ void CMesh::load(void) { m_indexCount = m_indexes.size(); // 5. détruire le staging buffer vmaDestroyBuffer(allocator, stagingBuffer.buffer, stagingBuffer.allocation); -} - -/*void CMesh::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) { - -}*/ +} \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.hpp b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.hpp index 96c2a5f..a0ce1ed 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.hpp +++ b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh.hpp @@ -21,8 +21,6 @@ private: VkDeviceSize m_indexOffset = 0; uint32_t m_indexCount = 0; - //CMaterial* m_material; - public: CMesh(void); @@ -34,14 +32,9 @@ public: void setVertices(std::vector vertices); void setIndexes(std::vector indexes); - - //void setMaterial(CMaterial* mat){m_material = mat;}; void load(void); - //void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity); - - //CMaterial* getMaterial(){return m_material;}; VMABuffer& getVertexIndexBuffer(){return vertexIndexBuffer;}; VkDeviceSize getVertexOffset(){return m_vertexOffset;} VkDeviceSize getIndexOffset(){return m_indexOffset;}; diff --git a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.cpp b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.cpp new file mode 100644 index 0000000..0d348cd --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.cpp @@ -0,0 +1,157 @@ +#include "CMesh2D.hpp" +#include "../../API/VulkanImplementation/VulkanImpl.hpp" +#include "Core/Systems/Graphics/Data/Mesh/SVertex.hpp" +#include +#include +namespace CosmicCore { + + CMesh2D::CMesh2D(void) : + m_vertexes() { + } + + CMesh2D::~CMesh2D(void) { + destroy(); + } + + void CMesh2D::destroy() + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + api->destroyBuffer(vertexIndexBuffer, api->getCurrentFrameIndex()); + } + std::vector& CMesh2D::getVertices(void) { + return m_vertexes; + } + + + void CMesh2D::setVertices(std::vector vertices) + { + m_vertexes = vertices; + } + void CMesh2D::setIndexes(std::vector indexes){ + m_indexes = indexes; + } + + std::vector& CMesh2D::getIndexes(void){ + return m_indexes; + } + + void CMesh2D::load(void) { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + VmaAllocator allocator = api->getAllocator(); + + VkDeviceSize vertexSize = sizeof(m_vertexes[0]) * m_vertexes.size(); + VkDeviceSize indexSize = sizeof(m_indexes[0]) * m_indexes.size(); + VkDeviceSize totalSize = vertexSize + indexSize; + + // 1. staging buffer - CPU visible, temporaire + VkBufferCreateInfo stagingBufferInfo{}; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.size = totalSize; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + VmaAllocationCreateInfo stagingAllocInfo{}; + stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY; + stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; + + VMABuffer stagingBuffer; + VmaAllocationInfo stagingInfo{}; + vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocInfo, + &stagingBuffer.buffer, &stagingBuffer.allocation, &stagingInfo); + + // 2. copie des données CPU → staging + memcpy(stagingInfo.pMappedData, m_vertexes.data(), vertexSize); + memcpy((char*)stagingInfo.pMappedData + vertexSize, m_indexes.data(), indexSize); + vmaFlushAllocation(allocator, stagingBuffer.allocation, 0, VK_WHOLE_SIZE); + + // 3. vertex buffer final - DEVICE_LOCAL, rapide + VkBufferCreateInfo vertexBufferInfo{}; + vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vertexBufferInfo.size = totalSize; + vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT + | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + VmaAllocationCreateInfo vertexAllocInfo{}; + vertexAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; + + vmaCreateBuffer(allocator, &vertexBufferInfo, &vertexAllocInfo, + &vertexIndexBuffer.buffer, &vertexIndexBuffer.allocation, nullptr); + + // 4. copie GPU staging → vertex buffer via command buffer + api->copyBuffer(stagingBuffer.buffer, vertexIndexBuffer.buffer, totalSize); + + m_vertexOffset = 0; + m_indexOffset = vertexSize; + m_indexCount = m_indexes.size(); + // 5. détruire le staging buffer + vmaDestroyBuffer(allocator, stagingBuffer.buffer, stagingBuffer.allocation); + } + + glm::vec2 CMesh2D::buildFromText(CFont* font, const std::string& text) + { + //destroy check before load if text is edited ? + if (!font || text.empty()) { + setVertices({}); + setIndexes({}); + return {0.0f, 0.0f}; + } + + std::vector vertices; + std::vector indices; + + float scale = font->getMetrics().emSize; + float cursorX = 0.0f; + float cursorY = 0.0f; + float maxWidth = 0.0f; + int lineCount = 1; + + for (char c : text) { + if (c == '\n') { + maxWidth = std::max(maxWidth, cursorX); + cursorX = 0.0f; + cursorY += font->getMetrics().lineHeight * scale; + lineCount++; + continue; + } + + const SGlyph* glyph = font->getGlyph((uint32_t)c); + if (!glyph) continue; + + // positions des coins du quad (espace local au mesh) + glm::vec2 p0 = { + cursorX + glyph->planeMin.x * scale, + cursorY - glyph->planeMax.y * scale + }; + glm::vec2 p1 = { + cursorX + glyph->planeMax.x * scale, + cursorY - glyph->planeMin.y * scale + }; + + // UVs dans l'atlas — flip V pour Vulkan + glm::vec2 uv0 = {glyph->atlasMin.x, 1.0f - glyph->atlasMax.y}; + glm::vec2 uv1 = {glyph->atlasMax.x, 1.0f - glyph->atlasMin.y}; + + uint32_t base = (uint32_t)vertices.size(); + + vertices.push_back({{p0.x, p0.y}, {uv0.x, uv0.y}, {1, 1, 1, 1}}); + vertices.push_back({{p1.x, p0.y}, {uv1.x, uv0.y}, {1, 1, 1, 1}}); + vertices.push_back({{p1.x, p1.y}, {uv1.x, uv1.y}, {1, 1, 1, 1}}); + vertices.push_back({{p0.x, p1.y}, {uv0.x, uv1.y}, {1, 1, 1, 1}}); + + indices.insert(indices.end(), + {base, base+1, base+2, base+2, base+3, base}); + + cursorX += glyph->advance * scale; + } + + maxWidth = std::max(maxWidth, cursorX); + float totalHeight = lineCount * font->getMetrics().lineHeight * scale; + + setVertices(vertices); + setIndexes(indices); + load(); // upload GPU + + return {maxWidth, totalHeight}; + } + +} \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.hpp b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.hpp new file mode 100644 index 0000000..1037843 --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Mesh/CMesh2D.hpp @@ -0,0 +1,43 @@ +#ifndef CMESH2D_HPP +#define CMESH2D_HPP + +#include "Core/Systems/Graphics/API/VulkanImplementation/VMABuffer.hpp" +#include "Core/Systems/Graphics/Data/Font/CFont.hpp" +#include "Core/Systems/Graphics/Data/Mesh/SVertex.hpp" +namespace CosmicCore { + class CMesh2D + { + private: + std::vector m_vertexes; + std::vector m_indexes; + + VMABuffer vertexIndexBuffer; + VkDeviceSize m_vertexOffset = 0; + VkDeviceSize m_indexOffset = 0; + uint32_t m_indexCount = 0; + + public: + + CMesh2D(void); + + ~CMesh2D(void); + + std::vector& getVertices(void); + std::vector& getIndexes(void); + + void setVertices(std::vector vertices); + void setIndexes(std::vector indexes); + + void load(void); + + VMABuffer& getVertexIndexBuffer(){return vertexIndexBuffer;}; + VkDeviceSize getVertexOffset(){return m_vertexOffset;} + VkDeviceSize getIndexOffset(){return m_indexOffset;}; + uint32_t getIndexCount(){return m_indexCount;}; + void destroy(); + + glm::vec2 buildFromText(CFont* font, const std::string& text); + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Mesh/SVertex.hpp b/src/Engine/Core/Systems/Graphics/Data/Mesh/SVertex.hpp index ba759e3..356d952 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Mesh/SVertex.hpp +++ b/src/Engine/Core/Systems/Graphics/Data/Mesh/SVertex.hpp @@ -67,4 +67,30 @@ typedef struct SVertex{ } Vertex; +/** + * @brief the struct Vertex, use to represent vertex and vertex attribute. + */ + typedef struct SVertex2D{ + + glm::vec2 m_position; + glm::vec2 m_uv; + glm::vec4 m_color; + + + static vk::VertexInputBindingDescription getBindingDescription() { + return { 0, sizeof(SVertex2D), vk::VertexInputRate::eVertex }; + } + + static std::array getAttributeDescriptions() { + return {{ + {0, 0, vk::Format::eR32G32Sfloat, offsetof(SVertex2D, m_position)}, + {1, 0, vk::Format::eR32G32Sfloat, offsetof(SVertex2D, m_uv)}, + {2, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(SVertex2D, m_color)} + }}; + } + +} Vertex2D; + + + #endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Model/CModel.cpp b/src/Engine/Core/Systems/Graphics/Data/Model/CModel.cpp index faf0adc..b26771f 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Model/CModel.cpp +++ b/src/Engine/Core/Systems/Graphics/Data/Model/CModel.cpp @@ -8,22 +8,6 @@ CModel::CModel(std::vector meshes) : CModel::~CModel(void) { } -/*void CModel::load(void) { - // For each meshes of the model. - for (unsigned int i = 0; i < m_meshes.size(); i++) { - m_meshes[i]->load(); - } - - m_loaded = true; -}*/ - -/*void CModel::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) { - // For each meshes of the model. - for (unsigned int i = 0; i < m_meshes.size(); i++) { - m_meshes[i]->draw(model, view, projection, lightPos, intensity); - } -}*/ - std::vector& CModel::getMeshMaterials() { return m_meshes; diff --git a/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.cpp b/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.cpp new file mode 100644 index 0000000..39ffb84 --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.cpp @@ -0,0 +1,28 @@ +#include "CModel2D.hpp" + +namespace CosmicCore { + + CModel2D::CModel2D(std::vector meshes) : + m_meshes(meshes), + m_loaded(false) { + } + + CModel2D::~CModel2D(void) { + } + + std::vector& CModel2D::getMeshMaterials() + { + return m_meshes; + } + + void CModel2D::setMeshMaterials(std::vector meshes) + { + m_meshes = meshes; + } + + bool CModel2D::isLoaded() + { + return m_loaded; + } + +} \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.hpp b/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.hpp new file mode 100644 index 0000000..bbad1bc --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/Data/Model/CModel2D.hpp @@ -0,0 +1,36 @@ +#ifndef CMODEL2D_HPP +#define CMODEL2D_HPP + +#include "Core/Systems/Graphics/Data/Material/CMaterial2D.hpp" +#include "Core/Systems/Graphics/Data/Mesh/CMesh2D.hpp" +namespace CosmicCore { + struct MeshMaterial2D{ + CMesh2D* mesh = nullptr; + CMaterial2D* material = nullptr; + }; + + class CModel2D { + private: + + std::vector m_meshes; + + bool m_loaded; + + public: + + CModel2D(void) = delete; + + CModel2D(std::vector meshes); + + ~CModel2D(void); + + std::vector& getMeshMaterials(void); + + void setMeshMaterials(std::vector meshes); + + bool isLoaded(void); + + }; +} + +#endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Graphics/Data/Texture/CTexture.cpp b/src/Engine/Core/Systems/Graphics/Data/Texture/CTexture.cpp index f656426..48414f7 100644 --- a/src/Engine/Core/Systems/Graphics/Data/Texture/CTexture.cpp +++ b/src/Engine/Core/Systems/Graphics/Data/Texture/CTexture.cpp @@ -1,6 +1,7 @@ #include "CTexture.hpp" #include "../../API/VulkanImplementation/VulkanImpl.hpp" +#include CTexture::CTexture(std::string filePath) : m_filePath(filePath) { @@ -20,11 +21,10 @@ void CTexture::init(void) { // Read the image file. SDL_Surface* sdlSurface = IMG_Load(m_filePath.c_str()); - if(sdlSurface == nullptr) - { - //error here - } - + if (!sdlSurface) { + throw std::runtime_error("Failed to load: " + m_filePath); + } + SDL_PixelFormat sdlFormat = sdlSurface->format; SDL_Surface* converted = nullptr; @@ -50,7 +50,7 @@ void CTexture::init(void) { m_height = converted->h; VkDeviceSize imageSize = m_width * m_height * 4; - // 2. staging buffer + // staging buffer VkBufferCreateInfo stagingBufferInfo{}; stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; stagingBufferInfo.size = imageSize; @@ -69,7 +69,7 @@ void CTexture::init(void) { // Free the surface. SDL_DestroySurface(converted); - // 3. crée l'image GPU + // crée l'image GPU api->createImage( m_width, m_height, m_format, @@ -80,7 +80,7 @@ void CTexture::init(void) { m_textureImageMemory ); - // 4. transitions et copie + // transitions et copie api->transitionImageLayout(m_textureImage, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal); @@ -108,10 +108,10 @@ void CTexture::init(void) { vmaDestroyBuffer(api->getAllocator(), stagingBuffer.buffer, stagingBuffer.allocation); - // 5. image view + // image view m_imageView = api->createImageView(m_textureImage, m_format, vk::ImageAspectFlagBits::eColor); - // 6. sampler + // sampler vk::SamplerCreateInfo samplerInfo{}; samplerInfo.magFilter = vk::Filter::eLinear; samplerInfo.minFilter = vk::Filter::eLinear; @@ -134,7 +134,7 @@ void CTexture::initDefaultTexture() VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); auto* device= static_cast(api->getDevice()); - // pixel blanc 1x1 RGBA + // pixel rouge RGBA uint32_t whitePixel = 0x00000ff0; uint32_t width = 1; uint32_t height = 1; diff --git a/src/Engine/Core/Systems/Graphics/UserInterface/CUIWorld.hpp b/src/Engine/Core/Systems/Graphics/UserInterface/CUIWorld.hpp new file mode 100644 index 0000000..b7c5a0a --- /dev/null +++ b/src/Engine/Core/Systems/Graphics/UserInterface/CUIWorld.hpp @@ -0,0 +1 @@ +//TODO ??????? \ No newline at end of file diff --git a/src/Engine/Core/Systems/Input/CInputDispatcher.cpp b/src/Engine/Core/Systems/Input/CInputDispatcher.cpp index 8470087..a2f9b00 100644 --- a/src/Engine/Core/Systems/Input/CInputDispatcher.cpp +++ b/src/Engine/Core/Systems/Input/CInputDispatcher.cpp @@ -2,6 +2,8 @@ #include "../../Scene/CScene.hpp" #include "../../Component/Input/CInputManager.hpp" #include "Core/Systems/Input/API/CInputAPI.hpp" +#include +#include #include namespace CosmicCore { @@ -21,6 +23,10 @@ namespace CosmicCore { // reset souris relative après dispatch m_mouseRelative = {0, 0}; + genericLeftMouseButtonJustClicked = false; + genericLeftMouseButtonJustReleased = false; + genericRightMouseButtonJustClicked = false; + genericRightMouseButtonJustReleased = false; } void CInputDispatcher::processEvent(const SDL_Event& event) @@ -46,6 +52,25 @@ namespace CosmicCore { } break; } + + case SDL_EVENT_MOUSE_BUTTON_DOWN: { + switch (event.button.button) { + case SDL_BUTTON_LEFT: genericLeftMouseButtonJustClicked = true; genericLeftMouseButtonJustReleased = false; break; + case SDL_BUTTON_RIGHT: genericRightMouseButtonJustClicked = true; genericRightMouseButtonJustReleased = false; break; + default: break; + } + break; + } + + case SDL_EVENT_MOUSE_BUTTON_UP: { + switch (event.button.button) { + case SDL_BUTTON_LEFT: genericLeftMouseButtonJustReleased = true; genericLeftMouseButtonJustClicked = false; break; + case SDL_BUTTON_RIGHT: genericRightMouseButtonJustReleased = true; genericRightMouseButtonJustClicked = false; break; + default: break; + } + break; + } + case SDL_EVENT_MOUSE_MOTION: { m_mouseRelative = {event.motion.xrel, event.motion.yrel}; m_mousePosition = {event.motion.x, event.motion.y}; diff --git a/src/Engine/Core/Systems/Input/CInputDispatcher.hpp b/src/Engine/Core/Systems/Input/CInputDispatcher.hpp index b5e9123..989794b 100644 --- a/src/Engine/Core/Systems/Input/CInputDispatcher.hpp +++ b/src/Engine/Core/Systems/Input/CInputDispatcher.hpp @@ -19,6 +19,12 @@ namespace CosmicCore { glm::vec2 m_mouseRelative = {0, 0}; glm::vec2 m_mousePosition = {0, 0}; CInputMapping m_mapping; + //Todo left and right click ? + bool genericLeftMouseButtonJustClicked = false; + bool genericLeftMouseButtonJustReleased = false; + + bool genericRightMouseButtonJustClicked = false; + bool genericRightMouseButtonJustReleased = false; public: CInputDispatcher() {} @@ -28,6 +34,11 @@ namespace CosmicCore { void processEvent(const SDL_Event& event); + bool isLeftMouseButtonJustClicked() const {return genericLeftMouseButtonJustClicked;}; + bool isLeftMouseButtonJustReleased() const {return genericLeftMouseButtonJustReleased;}; + bool isRightMouseButtonJustClicked() const {return genericRightMouseButtonJustClicked;}; + bool isRightMouseButtonJustReleased() const {return genericRightMouseButtonJustReleased;}; + glm::vec2 getMouseRelative() const { return m_mouseRelative; } glm::vec2 getMousePosition() const { return m_mousePosition; } float getSensitivity() const { return m_mapping.getMouseSensitivity(); } diff --git a/src/Engine/Core/Systems/Resources/CResourceManager.hpp b/src/Engine/Core/Systems/Resources/CResourceManager.hpp index 80ea6eb..37b01c4 100644 --- a/src/Engine/Core/Systems/Resources/CResourceManager.hpp +++ b/src/Engine/Core/Systems/Resources/CResourceManager.hpp @@ -7,6 +7,7 @@ #include "Audio/CAudioManager.hpp" #include "Shader/CShadersManager.hpp" #include "Texture/CTextureManager.hpp" +#include "Font/CFontManager.hpp" class CResourceManager{ private: @@ -16,6 +17,10 @@ class CResourceManager{ CTextureManager m_textureManager; CAudioManager m_audioManager; CShadersManager m_shaderManager; + CFontManager m_fontManager; + CModel2DManager m_model2DManager; + CMaterial2DManager m_material2DManager; + CMesh2DManager m_mesh2DManager; public: CModelManager& models() { return m_modelManager; } CMeshManager& meshes() { return m_meshManager; } @@ -23,6 +28,10 @@ class CResourceManager{ CTextureManager& textures() { return m_textureManager; } CAudioManager& sounds() { return m_audioManager; } CShadersManager& shaders() { return m_shaderManager; } + CFontManager& fonts() { return m_fontManager; } + CModel2DManager& models2D() {return m_model2DManager;} + CMaterial2DManager& materials2D() {return m_material2DManager;} + CMesh2DManager& meshes2D() { return m_mesh2DManager; } const CModelManager& models() const { return m_modelManager; } const CMeshManager& meshes() const { return m_meshManager; } @@ -30,6 +39,10 @@ class CResourceManager{ const CTextureManager& textures() const { return m_textureManager; } const CAudioManager& sounds() const { return m_audioManager; } const CShadersManager& shaders() const { return m_shaderManager; } + const CFontManager& fonts() const { return m_fontManager; } + const CModel2DManager& models2D() const {return m_model2DManager;} + const CMaterial2DManager& materials2D() const {return m_material2DManager;} + const CMesh2DManager& meshes2D() const { return m_mesh2DManager; } void cleanup() { m_modelManager.clear(); @@ -37,6 +50,10 @@ class CResourceManager{ m_meshManager.clear(); m_textureManager.clear(); m_audioManager.clear(); + m_fontManager.clear(); + m_model2DManager.clear(); + m_material2DManager.clear(); + m_mesh2DManager.clear(); m_shaderManager.clear(); } }; diff --git a/src/Engine/Core/Systems/Resources/Font/CFontManager.hpp b/src/Engine/Core/Systems/Resources/Font/CFontManager.hpp new file mode 100644 index 0000000..575cef8 --- /dev/null +++ b/src/Engine/Core/Systems/Resources/Font/CFontManager.hpp @@ -0,0 +1,48 @@ +#ifndef CFONTMANAGER_HPP +#define CFONTMANAGER_HPP + +#include "../../Graphics/Data/Font/CFont.hpp" + +#include "../CAbstractResourceManager.hpp" +#include +#include +#include + +class CFontManager : public CAbstractResourceManager +{ + public: + + CosmicCore::CFont* loadFont(const std::string& path) { + auto cached = get(path); + if (cached) return cached.value(); + std::optional jsonPath = std::nullopt; + std::optional pngPath = std::nullopt; + + for (const auto& entry : std::filesystem::directory_iterator(path)) + { + if(entry.is_regular_file()) + { + // Converting the path to const char * in the + // subsequent lines + std::filesystem::path extension = entry.path().extension(); + if(extension == ".json") + { + jsonPath = entry.path().string(); + } + else if(extension == ".png") + { + pngPath = entry.path().string(); + } + } + } + if(!jsonPath || !pngPath) + { + throw std::runtime_error("Font is not a valid folder. Must contain a json and a png"); + } + auto font = std::make_unique(); + font->init(*jsonPath, *pngPath); + return add(path, std::move(font)); + } +}; + + #endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Resources/Material/CMaterialManager.hpp b/src/Engine/Core/Systems/Resources/Material/CMaterialManager.hpp index c161bc2..ef13dfe 100644 --- a/src/Engine/Core/Systems/Resources/Material/CMaterialManager.hpp +++ b/src/Engine/Core/Systems/Resources/Material/CMaterialManager.hpp @@ -2,8 +2,10 @@ #define CMATERIALMANAGER_HPP #include "../../Graphics/Data/Material/CMaterial.hpp" +#include "../../Graphics/Data/Material/CMaterial2D.hpp" #include "../CAbstractResourceManager.hpp" +#include "Core/Systems/Graphics/Data/Texture/CTexture.hpp" class CMaterialManager : public CAbstractResourceManager { @@ -21,5 +23,75 @@ class CMaterialManager : public CAbstractResourceManager return add(key, std::move(mat)); } }; +using namespace CosmicCore; +class CMaterial2DManager : public CAbstractResourceManager +{ + public: + /*CMaterial2D* createRectMaterial(const std::string& key, + glm::vec4 color, + CShaderImplVulkan* shader) + { + auto mat = std::make_unique(); + mat->m_shapeType = E2DShapeType::Rect; + mat->shader = shader; + mat->m_color = color; + mat->build(); + return add(key, std::move(mat)); + } + + CMaterial2D* createCircleMaterial(const std::string& key, + glm::vec4 color, + CShaderImplVulkan* shader) + { + auto mat = std::make_unique(); + mat->m_shapeType = E2DShapeType::Circle; + mat->shader = shader; + mat->m_color = color; + mat->build(); + return add(key, std::move(mat)); + } + + CMaterial2D* createRoundedRectMaterial(const std::string& key, + glm::vec4 color, + float radius, + CShaderImplVulkan* shader) + { + auto mat = std::make_unique(); + mat->m_shapeType = E2DShapeType::RoundedRect; + mat->shader = shader; + mat->m_color = color; + mat->m_cornerRadius = radius; + mat->build(); + return add(key, std::move(mat)); + } + + CMaterial2D* createTextureMaterial(const std::string& key, + glm::vec4 color, + CTexture* texture, + CShaderImplVulkan* shader) + { + auto mat = std::make_unique(); + mat->m_shapeType = E2DShapeType::Rect; + mat->shader = shader; + mat->m_color = color; + mat->m_texture = texture; + mat->build(); + return add(key, std::move(mat)); + } + + CMaterial2D* createText(const std::string& key, + glm::vec4 color, + CFont* font, + CShaderImplVulkan* shader) + { + auto mat = std::make_unique(); + mat->m_shapeType = E2DShapeType::Rect; + mat->shader = shader; + mat->m_color = color; + mat->m_font = font; + mat->build(); + return add(key, std::move(mat)); + }*/ +}; #endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Resources/Mesh/CMeshManager.hpp b/src/Engine/Core/Systems/Resources/Mesh/CMeshManager.hpp index b4b30cd..2971274 100644 --- a/src/Engine/Core/Systems/Resources/Mesh/CMeshManager.hpp +++ b/src/Engine/Core/Systems/Resources/Mesh/CMeshManager.hpp @@ -2,10 +2,16 @@ #define CMESHMANAGER_HPP #include "../../Graphics/Data/Mesh/CMesh.hpp" +#include "../../Graphics/Data/Mesh/CMesh2D.hpp" + #include "../CAbstractResourceManager.hpp" class CMeshManager : public CAbstractResourceManager { +}; + +class CMesh2DManager : public CAbstractResourceManager +{ }; #endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Resources/Model/CModelManager.hpp b/src/Engine/Core/Systems/Resources/Model/CModelManager.hpp index d953e98..6c55400 100644 --- a/src/Engine/Core/Systems/Resources/Model/CModelManager.hpp +++ b/src/Engine/Core/Systems/Resources/Model/CModelManager.hpp @@ -2,10 +2,16 @@ #define CMODELMANAGER_HPP #include "../../Graphics/Data//Model/CModel.hpp" +#include "../../Graphics/Data//Model/CModel2D.hpp" #include "../CAbstractResourceManager.hpp" + class CModelManager : public CAbstractResourceManager { +}; + +class CModel2DManager : public CAbstractResourceManager +{ }; #endif \ No newline at end of file diff --git a/src/Engine/Core/Systems/Scripts/API/CScriptAPI.cpp b/src/Engine/Core/Systems/Scripts/API/CScriptAPI.cpp index e50c0d0..45e4645 100644 --- a/src/Engine/Core/Systems/Scripts/API/CScriptAPI.cpp +++ b/src/Engine/Core/Systems/Scripts/API/CScriptAPI.cpp @@ -1,5 +1,6 @@ #include "CScriptAPI.hpp" #include +#include namespace CosmicCore { CScriptRegistry CScriptAPI::scriptRegistry; @@ -11,6 +12,10 @@ namespace CosmicCore { auto registerFunc = (void(*)(CScriptRegistry* reg))dlsym(lib, "registerAllScripts"); registerFunc(&CScriptAPI::scripts()); // Passer l'API à la lib } + else { + std::cout << "dlopen failed: " << dlerror() << std::endl; + throw std::runtime_error("Failed to load script module"); + } } } diff --git a/src/Engine/Utils/Factory/CEntityFactory.cpp b/src/Engine/Utils/Factory/CEntityFactory.cpp index af647d9..1face4b 100644 --- a/src/Engine/Utils/Factory/CEntityFactory.cpp +++ b/src/Engine/Utils/Factory/CEntityFactory.cpp @@ -60,6 +60,41 @@ CEntity create(CScene* scene, EntityConfig& config) { return entity; } +CEntity create(CScene* scene, Entity2DConfig& config) { + auto entity = scene->createEntity(); + ComponentFactory::addMetaData(entity, config.name, config.description); + auto& transform = config.transformConfig; + auto& camera = config.cameraConfig; + auto& collider = config.colliderConfig; + auto& renderer = config.rendererConfig; + auto& script = config.scriptConfig; + + if(transform.has_value()) + { + ComponentFactory::addTransform2D(entity, *transform); + } + if(renderer.has_value()) + { + ComponentFactory::addRenderer2D(entity, *renderer); + } + if(collider.has_value()) + { + ComponentFactory::addCollider2D(entity, *collider); + } + + if(camera.has_value()) + { + ComponentFactory::addCamera2D(entity, *camera); + } + + if(script.has_value()) + { + ComponentFactory::addScript(entity, *script); + } + return entity; +} + + /*CEntity* CEntityFactory::createCylinder(CScene* e, const EntityConfig& config) { std::string name = "Cylindre" + std::to_string(CEntity::entityNumber); CEntity* cylindre = new CEntity(name, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); diff --git a/src/Engine/Utils/Factory/CEntityFactory.hpp b/src/Engine/Utils/Factory/CEntityFactory.hpp index 8307c87..aef7067 100644 --- a/src/Engine/Utils/Factory/CEntityFactory.hpp +++ b/src/Engine/Utils/Factory/CEntityFactory.hpp @@ -23,7 +23,18 @@ namespace CosmicUtils { std::optional relationshipConfig = std::nullopt; }; + struct Entity2DConfig { + std::string name = "Entity"; + std::string description = ""; + std::optional transformConfig = std::nullopt; + std::optional cameraConfig = std::nullopt; + std::optional rendererConfig = std::nullopt; + std::optional colliderConfig = std::nullopt; + std::optional scriptConfig = std::nullopt; + }; + CEntity create(CScene* e, EntityConfig& config); + CEntity create(CScene* e, Entity2DConfig& config); /*CEntity createSphere(CScene* e, const EntityConfig& config); diff --git a/src/Engine/Utils/Factory/ComponentFactory.cpp b/src/Engine/Utils/Factory/ComponentFactory.cpp index 72cab4d..2837975 100644 --- a/src/Engine/Utils/Factory/ComponentFactory.cpp +++ b/src/Engine/Utils/Factory/ComponentFactory.cpp @@ -1,6 +1,9 @@ #include "ComponentFactory.hpp" #include "../../Core/Systems/Graphics/Data/CModelLoader.hpp" #include "../../Core/Systems/Resources/API/CResourceAPI.hpp" +#include "Core/Component/Camera/CCamera2D.hpp" +#include "Core/Component/Collider/CCollider2D.hpp" +#include "Core/Component/Geometry/CTransform2D.hpp" #include "Core/Component/Light/CLight.hpp" namespace CosmicUtils { @@ -170,7 +173,6 @@ namespace CosmicUtils { CLight& addLight(CEntity& entity, LightConfig& lightConfig) { - auto& rm = CResourceAPI::resources(); auto& reg = entity.getRegistry(); if (!reg.registry.all_of(*entity)) throw std::runtime_error("addLight requires a CTransform on the entity"); @@ -187,6 +189,60 @@ namespace CosmicUtils { return light; } + CCamera2D& addCamera2D(CEntity& entity, Camera2DConfig& cameraConfig) + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + auto& reg = entity.getRegistry(); + + // CTransform obligatoire pour la caméra + if (!reg.registry.all_of(*entity)) + throw std::runtime_error("addCamera2D requires a CTransform2D on the entity"); + + auto& transform = reg.registry.get(*entity); + auto& camera = reg.registry.emplace(*entity, entity); + camera.initUniformBuffer(api->getAllocator()); + camera.updateUniformBuffer(0, transform); + camera.updateUniformBuffer(1, transform); + return camera; + } + + CCollider2D& addCollider2D(CEntity& entity, Collider2DConfig& colliderConfig) + { + auto& reg = entity.getRegistry(); + auto& collider = reg.registry.emplace(*entity, entity, colliderConfig.shape); + return collider; + } + + CTransform2D& addTransform2D(CEntity& entity, Transform2DConfig& transformConfig) + { + VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); + + auto& reg = entity.getRegistry(); + auto& transform = reg.registry.emplace(*entity, entity); + transform.setSize(transformConfig.m_size); + transform.setPivot(transformConfig.m_pivot); + transform.setPosition(transformConfig.m_position); + transform.setScale(transformConfig.m_scale); + transform.setRotation(transformConfig.m_rotation); + transform.setVisible(transformConfig.m_visible); + transform.setZOrder(transformConfig.m_zOrder); + transform.initUniformBuffer(api->getAllocator()); + transform.updateUniformBuffer(0); + transform.updateUniformBuffer(1); + return transform; + } + + CRenderer2D& addRenderer2D(CEntity& entity, Renderer2DConfig& rendererConfig) + { + auto& reg = entity.getRegistry(); + + Model2DLoadConfig config; + config.shaderName = rendererConfig.shader; + + CModel2D* model = CModelLoader::loadModel2D(rendererConfig.model, config); + return reg.registry.emplace(*entity, entity, model); + } + } } \ No newline at end of file diff --git a/src/Engine/Utils/Factory/ComponentFactory.hpp b/src/Engine/Utils/Factory/ComponentFactory.hpp index 422d673..6afe725 100644 --- a/src/Engine/Utils/Factory/ComponentFactory.hpp +++ b/src/Engine/Utils/Factory/ComponentFactory.hpp @@ -10,6 +10,10 @@ #include "../../Core/Component/Meta/CMetaData.hpp" #include "../../Core/Component/Speaker/CSpeaker.hpp" #include "../../Core/Component/Relationships/CRelationship.hpp" +#include "Core/Component/Camera/CCamera2D.hpp" +#include "Core/Component/Collider/CCollider2D.hpp" +#include "Core/Component/Geometry/CTransform2D.hpp" +#include "Core/Component/Graphics/CRenderer2D.hpp" #include "Core/Component/Light/CLight.hpp" #include "Core/Component/Script/CScriptManager.hpp" #include "glm/ext/vector_float3.hpp" @@ -84,6 +88,28 @@ namespace CosmicUtils { bool castShadow = false; }; + struct Camera2DConfig{ + float zoom = 1; + }; + + struct Collider2DConfig{ + E2DShape shape = E2DShape::RECTANGLE; + }; + + struct Transform2DConfig{ + glm::vec2 m_position = {0, 0}; + glm::vec2 m_size = {100, 100}; + glm::vec2 m_scale = {1, 1}; + glm::vec2 m_pivot = {0, 0}; + float m_rotation = 0.0f; + float m_zOrder = 0.0f; + bool m_visible = true; + }; + + struct Renderer2DConfig{ + std::string model = ""; + std::string shader = "ui"; + }; // crée et initialise un CTransform sur une entité existante CTransform& addTransform(CEntity& entity, TransformConfig& transformConfig); @@ -109,6 +135,15 @@ namespace CosmicUtils { CScriptManager& addScript(CEntity& entity, ScriptConfig& scriptConfig); CLight& addLight(CEntity& entity, LightConfig& lightConfig); + + CCamera2D& addCamera2D(CEntity& entity, Camera2DConfig& cameraConfig); + + CCollider2D& addCollider2D(CEntity& entity, Collider2DConfig& colliderConfig); + + CTransform2D& addTransform2D(CEntity& entity, Transform2DConfig& transformConfig); + + CRenderer2D& addRenderer2D(CEntity& entity, Renderer2DConfig& rendererConfig); + }; } #endif diff --git a/src/Engine/Utils/JsonParser/Identifier.hpp b/src/Engine/Utils/JsonParser/Identifier.hpp index 08b62ab..c6360a5 100644 --- a/src/Engine/Utils/JsonParser/Identifier.hpp +++ b/src/Engine/Utils/JsonParser/Identifier.hpp @@ -77,7 +77,42 @@ namespace CosmicUtils { Light_Attenuation = 3075, Light_InnerAngle = 3076, Light_OuterAngle = 3077, - Light_CastShadow = 3078 + Light_CastShadow = 3078, + + + //2D + Scene_Entities2D = 104, + + // Entity + Entity2D_Ref = 207, + Entity2D_Name = 208, + Entity2D_Description = 209, + Entity2D_Components = 210, + + //ComponentList + Component_Transform2D= 2069, + Component_Renderer2D = 2070, + Component_Camera2D = 2071, + Component_Collider2D = 2072, + + // Transform + Transform_Position2D = 4011, + Transform_Rotation2D = 4012, + Transform_Scale2D = 4013, + Transform_Size2D = 4014, + Transform_Pivot2D = 4015, + Transform_zOrder2D = 4016, + Transform_Visible2D = 4017, + + // Renderer + Renderer_Model2D = 4021, + Renderer_Shader2D = 4022, + + //Camera + Camera_Zoom2D = 4031, + + // Collider + Collider_Shape2D = 4041 }; diff --git a/src/Modules/Scripts/UserScripts/CExampleScript.cpp b/src/Modules/Scripts/UserScripts/CExampleScript.cpp index fef7fd3..a8b5bb9 100644 --- a/src/Modules/Scripts/UserScripts/CExampleScript.cpp +++ b/src/Modules/Scripts/UserScripts/CExampleScript.cpp @@ -34,7 +34,7 @@ void CExampleScript::onCreate() .forward({0, 0, 0.05f}); }); - input.onMouseMove([](CEntity& e, glm::vec2 delta) { + input.addOnMouseMove([](CEntity& e, glm::vec2 delta) { auto& tr = e.getRegistry().registry.get(e.getHandle()); float sensitivity = 0.1f; glm::quat yaw = glm::angleAxis(