From 0a677e83a767da6615cbac2cd17fb55a4d3ed3a6 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Sun, 17 Aug 2025 12:17:41 +0800 Subject: [PATCH 01/12] feat: qt types serialization basics --- Editor/Include/Editor/QtGlue/Serialization.h | 257 +++++++++++++++++++ Editor/Src/QtGlue/Serialization.cpp | 5 + Editor/Src/Widget/ProjectHub.cpp | 2 - 3 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 Editor/Include/Editor/QtGlue/Serialization.h create mode 100644 Editor/Src/QtGlue/Serialization.cpp diff --git a/Editor/Include/Editor/QtGlue/Serialization.h b/Editor/Include/Editor/QtGlue/Serialization.h new file mode 100644 index 00000000..3165c8d3 --- /dev/null +++ b/Editor/Include/Editor/QtGlue/Serialization.h @@ -0,0 +1,257 @@ +// Created by Kindem on 2025/8/17. +// + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace Common { + template <> + struct Serializer { + static constexpr size_t typeId = HashUtils::StrCrc32("QString"); + + static size_t Serialize(BinarySerializeStream& outStream, const QString& inString) + { + return Serializer::Serialize(outStream, inString.toStdString()); + } + + static size_t Deserialize(BinaryDeserializeStream& inStream, QString& outString) + { + std::string stdString; + const size_t deserialized = Serializer::Deserialize(inStream, stdString); + outString = QString::fromStdString(stdString); + return deserialized; + } + }; + + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("QList") + + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& outStream, const QList& inList) + { + size_t serialized = Serializer::Serialize(outStream, inList.size()); + for (const auto& element : inList) { + serialized += Serializer::Serialize(outStream, element); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& inStream, QList& outList) + { + size_t deserialized = 0; + + outList.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(inStream, size); + + outList.reserve(size); + for (auto i = 0; i < size; i++) { + T element; + deserialized += Serializer::Deserialize(inStream, element); + outList.emplaceBack(std::move(element)); + } + return deserialized; + } + }; + + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("QSet") + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& outStream, const QSet& inSet) + { + size_t serialized = Serializer::Serialize(outStream, inSet.size()); + for (const auto& element : inSet) { + serialized += Serializer::Serialize(outStream, element); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& inStream, QSet& outSet) + { + size_t deserialized = 0; + + outSet.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(inStream, size); + + outSet.reserve(size); + for (auto i = 0; i < size; i++) { + T temp; + deserialized += Serializer::Deserialize(inStream, temp); + outSet.insert(std::move(temp)); + } + return deserialized; + } + }; + + template + struct Serializer> { + static constexpr size_t typeId + = HashUtils::StrCrc32("QMap") + + Serializer::typeId + + Serializer::typeId; + + static size_t Serialize(BinarySerializeStream& outStream, const QMap& inMap) + { + size_t serialized = Serializer::Serialize(outStream, inMap.size()); + for (const auto& [key, value] : inMap) { + serialized += Serializer::Serialize(outStream, key); + serialized += Serializer::Serialize(outStream, value); + } + return serialized; + } + + static size_t Deserialize(BinaryDeserializeStream& inStream, QMap& outMap) + { + size_t deserialized = 0; + + outMap.clear(); + uint64_t size; + deserialized += Serializer::Deserialize(inStream, size); + + for (auto i = 0; i < size; i++) { + K key; + V value; + deserialized += Serializer::Deserialize(inStream, key); + deserialized += Serializer::Deserialize(inStream, value); + outMap.insert(std::move(key), std::move(value)); + } + return deserialized; + } + }; + + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const QString& inValue) + { + const std::string stdString = inValue.toStdString(); + JsonSerializer::JsonSerialize(outJsonValue, inAllocator, stdString); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, QString& outValue) + { + std::string stdString; + JsonSerializer::JsonDeserialize(inJsonValue, stdString); + outValue = QString::fromStdString(stdString); + } + }; + + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const QList& inList) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inList.size(), inAllocator); + for (const auto& element : inList) { + rapidjson::Value jsonElement; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, element); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, QList& outList) + { + outList.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + outList.reserve(inJsonValue.Size()); + for (auto i = 0; i < inJsonValue.Size(); i++) { + T element; + JsonSerializer::JsonDeserialize(inJsonValue[i], element); + outList.emplaceBack(std::move(element)); + } + } + }; + + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const QSet& inSet) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inSet.size(), inAllocator); + for (const auto& element : inSet) { + rapidjson::Value jsonElement; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, element); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, QSet& outSet) + { + outSet.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + outSet.reserve(inJsonValue.Size()); + for (auto i = 0; i < inJsonValue.Size(); i++) { + T element; + JsonSerializer::JsonDeserialize(inJsonValue[i], element); + outSet.insert(std::move(element)); + } + } + }; + + template + struct JsonSerializer> { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const QMap& inMap) + { + outJsonValue.SetArray(); + outJsonValue.Reserve(inMap.size(), inAllocator); + for (const auto& [key, value] : inMap) { + rapidjson::Value jsonElement; + jsonElement.SetObject(); + + rapidjson::Value jsonKey; + JsonSerializer::JsonSerialize(jsonElement, inAllocator, key); + + rapidjson::Value jsonValue; + JsonSerializer::JsonSerialize(jsonValue, inAllocator, value); + + outJsonValue.AddMember("key", jsonKey, inAllocator); + outJsonValue.AddMember("value", jsonValue, inAllocator); + outJsonValue.PushBack(jsonElement, inAllocator); + } + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, QMap& outMap) + { + outMap.clear(); + + if (!inJsonValue.IsArray()) { + return; + } + for (auto i = 0; i < inJsonValue.Size(); i++) { + K key; + V value; + + const auto& jsonElement = inJsonValue[i]; + if (!jsonElement.IsObject()) { + continue; + } + if (jsonElement.HasMember("key")) { + JsonSerializer::JsonDeserialize(jsonElement["key"], key); + } + if (jsonElement.HasMember("value")) { + JsonSerializer::JsonDeserialize(jsonElement["value"], value); + } + outMap.insert(std::move(key), std::move(value)); + } + } + }; +} + diff --git a/Editor/Src/QtGlue/Serialization.cpp b/Editor/Src/QtGlue/Serialization.cpp new file mode 100644 index 00000000..cd2cfea1 --- /dev/null +++ b/Editor/Src/QtGlue/Serialization.cpp @@ -0,0 +1,5 @@ +// +// Created by johnk on 2025/8/17. +// + +#include diff --git a/Editor/Src/Widget/ProjectHub.cpp b/Editor/Src/Widget/ProjectHub.cpp index 6637f845..ab2ff952 100644 --- a/Editor/Src/Widget/ProjectHub.cpp +++ b/Editor/Src/Widget/ProjectHub.cpp @@ -2,8 +2,6 @@ // Created by johnk on 2025/8/3. // -#include - #include #include #include From 6646c2b8bda4f9316d38f1a188a967bf93d4ef11 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Mon, 18 Aug 2025 21:23:19 +0800 Subject: [PATCH 02/12] refactor: rename cmake utils functions --- CMake/Target.cmake | 64 ++++----- CMake/ThirdParty.cmake | 147 +++++---------------- Editor/CMakeLists.txt | 35 +++-- Engine/CMakeLists.txt | 2 +- Engine/Source/Common/CMakeLists.txt | 4 +- Engine/Source/Core/CMakeLists.txt | 4 +- Engine/Source/Launch/CMakeLists.txt | 2 +- Engine/Source/Mirror/CMakeLists.txt | 4 +- Engine/Source/RHI-DirectX12/CMakeLists.txt | 2 +- Engine/Source/RHI-Dummy/CMakeLists.txt | 2 +- Engine/Source/RHI-Vulkan/CMakeLists.txt | 2 +- Engine/Source/RHI/CMakeLists.txt | 2 +- Engine/Source/Render/CMakeLists.txt | 6 +- Engine/Source/Runtime/CMakeLists.txt | 4 +- Engine/Source/Test/CMakeLists.txt | 2 +- Sample/CMakeLists.txt | 16 +-- ThirdParty/CMakeLists.txt | 39 +++--- Tool/MirrorTool/CMakeLists.txt | 6 +- 18 files changed, 141 insertions(+), 202 deletions(-) diff --git a/CMake/Target.cmake b/CMake/Target.cmake index 076b9d4b..c4ce9e99 100644 --- a/CMake/Target.cmake +++ b/CMake/Target.cmake @@ -12,7 +12,7 @@ else() add_definitions(-DBUILD_TEST=0) endif() -function(CombineRuntimeDependencies) +function(exp_combine_runtime_deps) cmake_parse_arguments(PARAMS "" "NAME" "RUNTIME_DEP" ${ARGN}) get_target_property(RESULT ${PARAMS_NAME} RUNTIME_DEP) @@ -27,7 +27,7 @@ function(CombineRuntimeDependencies) ) endfunction() -function(LinkLibraries) +function(exp_link_libs) cmake_parse_arguments(PARAMS "" "NAME" "LIB" ${ARGN}) foreach(L ${PARAMS_LIB}) @@ -61,7 +61,7 @@ function(LinkLibraries) get_target_property(RUNTIME_DEP ${L} 3RD_RUNTIME_DEP) if (NOT ("${RUNTIME_DEP}" STREQUAL "RUNTIME_DEP-NOTFOUND")) - CombineRuntimeDependencies( + exp_combine_runtime_deps( NAME ${PARAMS_NAME} RUNTIME_DEP "${RUNTIME_DEP}" ) @@ -69,12 +69,12 @@ function(LinkLibraries) endforeach() endfunction() -function(LinkBasicLibs) +function(exp_link_basic_libs) cmake_parse_arguments(PARAMS "" "NAME" "LIB" ${ARGN}) foreach(L ${PARAMS_LIB}) if (NOT (${PARAMS_NAME} STREQUAL ${L})) - LinkLibraries( + exp_link_libs( NAME ${PARAMS_NAME} LIB ${L} ) @@ -82,7 +82,7 @@ function(LinkBasicLibs) endforeach() endfunction() -function(GetTargetRuntimeDependenciesRecurse) +function(exp_get_target_runtime_deps_recurse) cmake_parse_arguments(PARAMS "" "NAME;OUTPUT" "" ${ARGN}) get_target_property(RUNTIME_DEP ${PARAMS_NAME} RUNTIME_DEP) @@ -99,7 +99,7 @@ function(GetTargetRuntimeDependenciesRecurse) continue() endif() - GetTargetRuntimeDependenciesRecurse( + exp_get_target_runtime_deps_recurse( NAME ${L} OUTPUT TEMP ) @@ -113,10 +113,10 @@ function(GetTargetRuntimeDependenciesRecurse) set(${PARAMS_OUTPUT} ${RESULT} PARENT_SCOPE) endfunction() -function(AddRuntimeDependenciesCopyCommand) +function(exp_add_runtime_deps_copy_command) cmake_parse_arguments(PARAMS "NOT_INSTALL" "NAME" "" ${ARGN}) - GetTargetRuntimeDependenciesRecurse( + exp_get_target_runtime_deps_recurse( NAME ${PARAMS_NAME} OUTPUT RUNTIME_DEPS ) @@ -158,7 +158,7 @@ function(AddRuntimeDependenciesCopyCommand) endforeach() endfunction() -function(ExpandResourcePathExpression) +function(exp_expand_resource_path_expression) cmake_parse_arguments(PARAMS "" "INPUT;OUTPUT_SRC;OUTPUT_DST" "" ${ARGN}) string(REPLACE "->" ";" TEMP ${PARAMS_INPUT}) @@ -169,11 +169,11 @@ function(ExpandResourcePathExpression) set(${PARAMS_OUTPUT_DST} ${DST} PARENT_SCOPE) endfunction() -function(AddResourcesCopyCommand) +function(exp_add_resources_copy_command) cmake_parse_arguments(PARAMS "NOT_INSTALL" "NAME" "RES" ${ARGN}) foreach(R ${PARAMS_RES}) - ExpandResourcePathExpression( + exp_expand_resource_path_expression( INPUT ${R} OUTPUT_SRC SRC OUTPUT_DST DST @@ -196,7 +196,7 @@ function(AddResourcesCopyCommand) add_dependencies(${PARAMS_NAME} ${COPY_RES_TARGET_NAME}) endfunction() -function(GetTargetIncludeDirectoriesRecurse) +function(exp_get_target_include_dirs_recurse) cmake_parse_arguments(PARAMS "" "NAME;OUTPUT" "" ${ARGN}) if (NOT (TARGET ${PARAMS_NAME})) @@ -215,7 +215,7 @@ function(GetTargetIncludeDirectoriesRecurse) get_target_property(TARGET_LIBS ${PARAMS_NAME} LINK_LIBRARIES) if (NOT ("${TARGET_LIBS}" STREQUAL "TARGET_LIBS-NOTFOUND")) foreach(TARGET_LIB ${TARGET_LIBS}) - GetTargetIncludeDirectoriesRecurse( + exp_get_target_include_dirs_recurse( NAME ${TARGET_LIB} OUTPUT LIB_INCS ) @@ -237,7 +237,7 @@ function(GetTargetIncludeDirectoriesRecurse) set(${PARAMS_OUTPUT} ${RESULT} PARENT_SCOPE) endfunction() -function(AddMirrorInfoSourceGenerationTarget) +function(exp_add_mirror_info_source_generation_target) cmake_parse_arguments(PARAMS "DYNAMIC" "NAME;OUTPUT_SRC;OUTPUT_TARGET_NAME" "SEARCH_DIR;PUBLIC_INC;PRIVATE_INC;LIB" ${ARGN}) if (DEFINED PARAMS_PUBLIC_INC) @@ -248,7 +248,7 @@ function(AddMirrorInfoSourceGenerationTarget) endif() if (DEFINED PARAMS_LIB) foreach (L ${PARAMS_LIB}) - GetTargetIncludeDirectoriesRecurse( + exp_get_target_include_dirs_recurse( NAME ${L} OUTPUT TARGET_INCS ) @@ -301,7 +301,7 @@ function(AddMirrorInfoSourceGenerationTarget) endif() endfunction() -function(AddExecutable) +function(exp_add_executable) cmake_parse_arguments(PARAMS "SAMPLE;NOT_INSTALL" "NAME" "SRC;INC;LINK;LIB;DEP_TARGET;RES;REFLECT" ${ARGN}) if (${PARAMS_SAMPLE} AND (NOT ${BUILD_SAMPLE})) @@ -315,7 +315,7 @@ function(AddExecutable) endif () if (DEFINED PARAMS_REFLECT) - AddMirrorInfoSourceGenerationTarget( + exp_add_mirror_info_source_generation_target( NAME ${PARAMS_NAME} OUTPUT_SRC GENERATED_SRC OUTPUT_TARGET_NAME GENERATED_TARGET @@ -338,19 +338,19 @@ function(AddExecutable) ${PARAMS_NAME} PRIVATE ${PARAMS_LINK} ) - LinkBasicLibs( + exp_link_basic_libs( NAME ${PARAMS_NAME} LIB ${BASIC_LIBS} ) - LinkLibraries( + exp_link_libs( NAME ${PARAMS_NAME} LIB ${PARAMS_LIB} ) - AddRuntimeDependenciesCopyCommand( + exp_add_runtime_deps_copy_command( NAME ${PARAMS_NAME} ${NOT_INSTALL_FLAG} ) - AddResourcesCopyCommand( + exp_add_resources_copy_command( NAME ${PARAMS_NAME} RES ${PARAMS_RES} ${NOT_INSTALL_FLAG} @@ -378,7 +378,7 @@ function(AddExecutable) endif () endfunction() -function(AddLibrary) +function(exp_add_library) cmake_parse_arguments(PARAMS "NOT_INSTALL" "NAME;TYPE" "SRC;PRIVATE_INC;PUBLIC_INC;PRIVATE_LINK;LIB;REFLECT" ${ARGN}) if ("${PARAMS_TYPE}" STREQUAL "SHARED") @@ -390,7 +390,7 @@ function(AddLibrary) list(APPEND EXTRA_PARAMS DYNAMIC) endif () - AddMirrorInfoSourceGenerationTarget( + exp_add_mirror_info_source_generation_target( NAME ${PARAMS_NAME} OUTPUT_SRC GENERATED_SRC OUTPUT_TARGET_NAME GENERATED_TARGET @@ -420,11 +420,11 @@ function(AddLibrary) PRIVATE ${PARAMS_PRIVATE_LINK} PUBLIC ${PARAMS_PUBLIC_LINK} ) - LinkBasicLibs( + exp_link_basic_libs( NAME ${PARAMS_NAME} LIB ${BASIC_LIBS} ) - LinkLibraries( + exp_link_libs( NAME ${PARAMS_NAME} LIB ${PARAMS_LIB} ) @@ -481,7 +481,7 @@ function(AddLibrary) endif () endfunction() -function(AddTest) +function(exp_add_test) if (NOT ${BUILD_TEST}) return() endif() @@ -489,7 +489,7 @@ function(AddTest) cmake_parse_arguments(PARAMS "META" "NAME" "SRC;INC;LINK;LIB;DEP_TARGET;RES;REFLECT" ${ARGN}) if (DEFINED PARAMS_REFLECT) - AddMirrorInfoSourceGenerationTarget( + exp_add_mirror_info_source_generation_target( NAME ${PARAMS_NAME} OUTPUT_SRC GENERATED_SRC OUTPUT_TARGET_NAME GENERATED_TARGET @@ -512,19 +512,19 @@ function(AddTest) ${PARAMS_NAME} PRIVATE ${PARAMS_LINK} ) - LinkBasicLibs( + exp_link_basic_libs( NAME ${PARAMS_NAME} LIB ${BASIC_LIBS} ${BASIC_TEST_LIBS} ) - LinkLibraries( + exp_link_libs( NAME ${PARAMS_NAME} LIB ${PARAMS_LIB} ) - AddRuntimeDependenciesCopyCommand( + exp_add_runtime_deps_copy_command( NAME ${PARAMS_NAME} NOT_INSTALL ) - AddResourcesCopyCommand( + exp_add_resources_copy_command( NAME ${PARAMS_NAME} RES ${PARAMS_RES} NOT_INSTALL diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index bdbd9e33..98c94370 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -12,7 +12,7 @@ set(3RD_SOURCE_DIR ${3RD_DIR}/Lib CACHE PATH "" FORCE) set(3RD_BINARY_DIR ${CMAKE_BINARY_DIR}/ThirdPartyBuild CACHE PATH "" FORCE) set(3RD_INSTALL_DIR ${CMAKE_BINARY_DIR}/ThirdPartyInstall CACHE PATH "" FORCE) -function(DownloadAndExtract3rdPackage) +function(exp_download_and_extract_3rd_package) cmake_parse_arguments(PARAMS "" "URL;SAVE_AS;EXTRACT_TO;HASH" "ARG" ${ARGN}) if (EXISTS ${PARAMS_SAVE_AS}) @@ -42,7 +42,7 @@ function(DownloadAndExtract3rdPackage) endif() endfunction() -function(Expand3rdPathExpression) +function(exp_expand_3rd_path_expression) cmake_parse_arguments(PARAMS "" "OUTPUT;SOURCE_DIR;BINARY_DIR;INSTALL_DIR" "INPUT" ${ARGN}) foreach(I ${PARAMS_INPUT}) @@ -62,7 +62,7 @@ function(Expand3rdPathExpression) set(${PARAMS_OUTPUT} ${RESULT} PARENT_SCOPE) endfunction() -function(Get3rdPlatformValue) +function(exp_get_3rd_platform_value) cmake_parse_arguments(PARAMS "ARCH" "OUTPUT" "INPUT" ${ARGN}) if (${PARAMS_ARCH}) @@ -120,7 +120,7 @@ function(Get3rdPlatformValue) endif() endfunction() -function(Add3rdHeaderOnlyPackage) +function(exp_add_3rd_header_only_package) cmake_parse_arguments(PARAMS "" "NAME;PLATFORM;VERSION" "HASH;INCLUDE" ${ARGN}) set(NAME "${PARAMS_NAME}") @@ -138,11 +138,11 @@ function(Add3rdHeaderOnlyPackage) set(ZIP "${3RD_ZIP_DIR}/${FULL_NAME}.7z") set(SOURCE_DIR "${3RD_SOURCE_DIR}/${FULL_NAME}") - Get3rdPlatformValue( + exp_get_3rd_platform_value( OUTPUT HASH_VALUE INPUT ${PARAMS_HASH} ) - DownloadAndExtract3rdPackage( + exp_download_and_extract_3rd_package( URL ${URL} SAVE_AS ${ZIP} EXTRACT_TO ${SOURCE_DIR} @@ -156,12 +156,12 @@ function(Add3rdHeaderOnlyPackage) ) if (DEFINED PARAMS_INCLUDE) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_INCLUDE} OUTPUT R_INCLUDE SOURCE_DIR ${SOURCE_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( OUTPUT P_INCLUDE INPUT ${R_INCLUDE} ) @@ -172,7 +172,7 @@ function(Add3rdHeaderOnlyPackage) endif() endfunction() -function(Add3rdBinaryPackage) +function(exp_add_3rd_binary_package) cmake_parse_arguments(PARAMS "ARCH" "NAME;PLATFORM" "VERSION;HASH;INCLUDE;LINK;LIB;RUNTIME_DEP" ${ARGN}) set(NAME "${PARAMS_NAME}") @@ -182,7 +182,7 @@ function(Add3rdBinaryPackage) set(COUNT_ARCH "") endif() - Get3rdPlatformValue( + exp_get_3rd_platform_value( ${COUNT_ARCH} OUTPUT VERSION_VALUE INPUT ${PARAMS_VERSION} @@ -205,12 +205,12 @@ function(Add3rdBinaryPackage) set(ZIP "${3RD_ZIP_DIR}/${FULL_NAME}.7z") set(SOURCE_DIR "${3RD_SOURCE_DIR}/${FULL_NAME}") - Get3rdPlatformValue( + exp_get_3rd_platform_value( ${COUNT_ARCH} OUTPUT HASH_VALUE INPUT ${PARAMS_HASH} ) - DownloadAndExtract3rdPackage( + exp_download_and_extract_3rd_package( URL ${URL} SAVE_AS ${ZIP} EXTRACT_TO ${SOURCE_DIR} @@ -224,12 +224,12 @@ function(Add3rdBinaryPackage) ) if (DEFINED PARAMS_INCLUDE) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_INCLUDE} OUTPUT R_INCLUDE SOURCE_DIR ${SOURCE_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( ${COUNT_ARCH} INPUT ${R_INCLUDE} OUTPUT P_INCLUDE @@ -241,12 +241,12 @@ function(Add3rdBinaryPackage) endif() if (DEFINED PARAMS_LINK) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_LINK} OUTPUT R_LINK SOURCE_DIR ${SOURCE_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( ${COUNT_ARCH} INPUT ${R_LINK} OUTPUT P_LINK @@ -258,12 +258,12 @@ function(Add3rdBinaryPackage) endif() if (DEFINED PARAMS_LIB) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_LIB} OUTPUT R_LIB SOURCE_DIR ${SOURCE_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( ${COUNT_ARCH} OUTPUT P_LIB INPUT ${R_LIB} @@ -275,12 +275,12 @@ function(Add3rdBinaryPackage) endif() if (DEFINED PARAMS_RUNTIME_DEP) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_RUNTIME_DEP} OUTPUT R_RUNTIME_DEP SOURCE_DIR ${SOURCE_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( INPUT ${R_RUNTIME_DEP} OUTPUT P_RUNTIME_DEP ) @@ -291,7 +291,7 @@ function(Add3rdBinaryPackage) endif() endfunction() -function(Add3rdCMakeProject) +function(exp_add_3rd_cmake_package) cmake_parse_arguments(PARAMS "" "NAME;PLATFORM;VERSION" "HASH;CMAKE_ARG;INCLUDE;LINK;LIB;RUNTIME_DEP" ${ARGN}) set(NAME "${PARAMS_NAME}") @@ -311,11 +311,11 @@ function(Add3rdCMakeProject) set(BINARY_DIR "${3RD_BINARY_DIR}/${NAME}") set(INSTALL_DIR "${3RD_INSTALL_DIR}/${NAME}/$") - Get3rdPlatformValue( + exp_get_3rd_platform_value( OUTPUT HASH_VALUE INPUT ${PARAMS_HASH} ) - DownloadAndExtract3rdPackage( + exp_download_and_extract_3rd_package( URL ${URL} SAVE_AS ${ZIP} EXTRACT_TO ${SOURCE_DIR} @@ -340,14 +340,14 @@ function(Add3rdCMakeProject) ) if (DEFINED PARAMS_INCLUDE) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_INCLUDE} OUTPUT R_INCLUDE SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} INSTALL_DIR ${INSTALL_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( INPUT ${R_INCLUDE} OUTPUT P_INCLUDE ) @@ -358,14 +358,14 @@ function(Add3rdCMakeProject) endif() if (DEFINED PARAMS_LINK) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_LINK} OUTPUT R_LINK SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} INSTALL_DIR ${INSTALL_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( INPUT ${R_LINK} OUTPUT P_LINK ) @@ -376,14 +376,14 @@ function(Add3rdCMakeProject) endif() if (DEFINED PARAMS_LIB) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_LIB} OUTPUT R_LIB SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} INSTALL_DIR ${INSTALL_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( INPUT ${R_LIB} OUTPUT P_LIB ) @@ -394,14 +394,14 @@ function(Add3rdCMakeProject) endif() if (DEFINED PARAMS_RUNTIME_DEP) - Expand3rdPathExpression( + exp_expand_3rd_path_expression( INPUT ${PARAMS_RUNTIME_DEP} OUTPUT R_RUNTIME_DEP SOURCE_DIR ${SOURCE_DIR} BINARY_DIR ${BINARY_DIR} INSTALL_DIR ${INSTALL_DIR} ) - Get3rdPlatformValue( + exp_get_3rd_platform_value( INPUT ${R_RUNTIME_DEP} OUTPUT P_RUNTIME_DEP ) @@ -412,7 +412,7 @@ function(Add3rdCMakeProject) endif() endfunction() -function(Add3rdAliasPackage) +function(exp_add_3rd_alias_package) cmake_parse_arguments(PARAMS "" "NAME;PLATFORM" "LIB" ${ARGN}) if ((NOT (${PARAMS_PLATFORM} STREQUAL "All")) AND (NOT (${PARAMS_PLATFORM} STREQUAL ${CMAKE_SYSTEM_NAME}))) @@ -427,84 +427,7 @@ function(Add3rdAliasPackage) ) endfunction() -function(Find3rdPackage) - cmake_parse_arguments(PARAMS "" "NAME;PACKAGE;PLATFORM;VERSION" "HASH;PREFIX;COMPONENTS;LIB;RUNTIME_DEP" ${ARGN}) - - set(NAME "${PARAMS_NAME}") - if (DEFINED PARAMS_PLATFORM) - if ((NOT (${PARAMS_PLATFORM} STREQUAL "All")) AND (NOT (${PARAMS_PLATFORM} STREQUAL ${CMAKE_SYSTEM_NAME}))) - return() - endif() - set(FULL_NAME "${PARAMS_NAME}-${PARAMS_PLATFORM}-${PARAMS_VERSION}") - else() - set(FULL_NAME "${PARAMS_NAME}-${CMAKE_SYSTEM_NAME}-${PARAMS_VERSION}") - endif() - set(URL "${3RD_REPO}/${FULL_NAME}.7z") - set(ZIP "${3RD_ZIP_DIR}/${FULL_NAME}.7z") - set(SOURCE_DIR "${3RD_SOURCE_DIR}/${FULL_NAME}") - - Get3rdPlatformValue( - OUTPUT HASH_VALUE - INPUT ${PARAMS_HASH} - ) - DownloadAndExtract3rdPackage( - URL ${URL} - SAVE_AS ${ZIP} - EXTRACT_TO ${SOURCE_DIR} - HASH ${HASH_VALUE} - ) - - if (DEFINED PARAMS_PREFIX) - Expand3rdPathExpression( - INPUT ${PARAMS_PREFIX} - OUTPUT R_PREFIX - SOURCE_DIR ${SOURCE_DIR} - ) - Get3rdPlatformValue( - OUTPUT P_PREFIX - INPUT ${R_PREFIX} - ) - list(APPEND CMAKE_PREFIX_PATH ${P_PREFIX}) - endif () - - find_package( - ${PARAMS_PACKAGE} REQUIRED - COMPONENTS ${PARAMS_COMPONENTS} - GLOBAL - ) - - if (NOT ${${PARAMS_PACKAGE}_FOUND}) - message(FATAL_ERROR "Found no package named ${PARAMS_PACKAGE}") - endif() - - add_custom_target(${NAME} ALL) - set_target_properties( - ${NAME} PROPERTIES - 3RD_TYPE "Package" - ) - set_target_properties( - ${NAME} PROPERTIES - 3RD_LIB "${PARAMS_LIB}" - ) - - if (DEFINED PARAMS_RUNTIME_DEP) - Expand3rdPathExpression( - INPUT ${PARAMS_RUNTIME_DEP} - OUTPUT R_RUNTIME_DEP - SOURCE_DIR ${SOURCE_DIR} - ) - Get3rdPlatformValue( - INPUT ${R_RUNTIME_DEP} - OUTPUT P_RUNTIME_DEP - ) - set_target_properties( - ${NAME} PROPERTIES - 3RD_RUNTIME_DEP "${P_RUNTIME_DEP}" - ) - endif() -endfunction() - -function(Setup3rdPackage) +function(exp_setup_3rd_package) cmake_parse_arguments(PARAMS "" "NAME;PLATFORM;VERSION" "HASH" ${ARGN}) set(NAME "${PARAMS_NAME}") @@ -520,11 +443,11 @@ function(Setup3rdPackage) set(ZIP "${3RD_ZIP_DIR}/${FULL_NAME}.7z") set(SOURCE_DIR "${3RD_SOURCE_DIR}/${FULL_NAME}") - Get3rdPlatformValue( + exp_get_3rd_platform_value( OUTPUT HASH_VALUE INPUT ${PARAMS_HASH} ) - DownloadAndExtract3rdPackage( + exp_download_and_extract_3rd_package( URL ${URL} SAVE_AS ${ZIP} EXTRACT_TO ${SOURCE_DIR} diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index b5163e27..6e869fa7 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -12,13 +12,30 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(BUNDLE_INSTALL_DESTINATION BUNDLE DESTINATION ${CMAKE_INSTALL_PREFIX}/Engine/Binaries) endif () +set(EDITOR_INCLUDES Include) +set(EDITOR_QT_LIBS Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick Qt6::WebEngineWidgets) +set(EDITOR_LIBS Core RHI Runtime cpp-httplib ${EDITOR_QT_LIBS}) + +foreach (QT_LIB ${EDITOR_QT_LIBS}) + string(REPLACE "::" "" QT_RAW_LIB ${QT_LIB}) + list(APPEND EDITOR_INCLUDES ${${QT_RAW_LIB}_INCLUDE_DIRS}) +endforeach () + +exp_add_mirror_info_source_generation_target( + NAME Editor + OUTPUT_SRC EDITOR_MIRROR_GENERATED_SRC + OUTPUT_TARGET_NAME EDITOR_MIRROR_GENERATED_TARGET + SEARCH_DIR Include + PRIVATE_INC ${EDITOR_INCLUDES} + LIB ${EDITOR_LIBS} +) + file(GLOB_RECURSE SOURCES Src/*.cpp) -qt_add_executable(Editor ${PLATFORM_EXECUTABLE_HINT} ${SOURCES}) -target_include_directories(Editor PRIVATE Include) -target_include_directories(Editor PRIVATE ${CPP_HTTP_LIB_SOURCE_DIR}) -LinkLibraries( +qt_add_executable(Editor ${PLATFORM_EXECUTABLE_HINT} ${SOURCES} ${EDITOR_MIRROR_GENERATED_SRC}) +target_include_directories(Editor PRIVATE ${EDITOR_INCLUDES}) +exp_link_libs( NAME Editor - LIB Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick Qt6::WebEngineWidgets + LIB ${EDITOR_LIBS} ) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") @@ -26,9 +43,9 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") else() set(RHI_DEP_TARGETS RHI-Vulkan) endif() -add_dependencies(Editor ${RHI_DEP_TARGETS}) +add_dependencies(Editor ${EDITOR_MIRROR_GENERATED_TARGET} ${RHI_DEP_TARGETS}) -AddRuntimeDependenciesCopyCommand( +exp_add_runtime_deps_copy_command( NAME Editor ) install( @@ -81,7 +98,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") endif () # ---- begin shaders --------------------------------------------------------------------------------- -GetEngineShaderResources( +get_engine_shader_resources( NAME Editor OUTPUT EDITOR_RESOURCES ) @@ -93,7 +110,7 @@ foreach (SHADER ${SHADERS}) list(APPEND EDITOR_RESOURCES ${SHADER}->${COPY_DST}) endforeach () -AddResourcesCopyCommand( +exp_add_resources_copy_command( NAME Editor RES ${EDITOR_RESOURCES} ) diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 31b14731..dfc9b66f 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(Source) -function(GetEngineShaderResources) +function(get_engine_shader_resources) cmake_parse_arguments(PARAMS "" "NAME" "OUTPUT" ${ARGN}) file(GLOB_RECURSE ENGINE_SHADERS ${CMAKE_SOURCE_DIR}/Engine/Shader/*.es*) diff --git a/Engine/Source/Common/CMakeLists.txt b/Engine/Source/Common/CMakeLists.txt index 2f0855bf..994ebea7 100644 --- a/Engine/Source/Common/CMakeLists.txt +++ b/Engine/Source/Common/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB_RECURSE SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Common TYPE STATIC SRC ${SOURCES} @@ -8,7 +8,7 @@ AddLibrary( ) file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( +exp_add_test( NAME Common.Test INC Test SRC ${TEST_SOURCES} diff --git a/Engine/Source/Core/CMakeLists.txt b/Engine/Source/Core/CMakeLists.txt index ba89aa5e..f22b0413 100644 --- a/Engine/Source/Core/CMakeLists.txt +++ b/Engine/Source/Core/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Core TYPE SHARED SRC ${SOURCES} @@ -8,7 +8,7 @@ AddLibrary( ) file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( +exp_add_test( NAME Core.Test SRC ${TEST_SOURCES} LIB Core diff --git a/Engine/Source/Launch/CMakeLists.txt b/Engine/Source/Launch/CMakeLists.txt index d1be1329..f7e94cf6 100644 --- a/Engine/Source/Launch/CMakeLists.txt +++ b/Engine/Source/Launch/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB_RECURSE SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Launch TYPE STATIC SRC ${SOURCES} diff --git a/Engine/Source/Mirror/CMakeLists.txt b/Engine/Source/Mirror/CMakeLists.txt index 8ca6dcfa..4b7bfa92 100644 --- a/Engine/Source/Mirror/CMakeLists.txt +++ b/Engine/Source/Mirror/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Mirror TYPE SHARED SRC ${SOURCES} @@ -7,7 +7,7 @@ AddLibrary( ) file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( +exp_add_test( NAME Mirror.Test SRC ${TEST_SOURCES} LIB Mirror diff --git a/Engine/Source/RHI-DirectX12/CMakeLists.txt b/Engine/Source/RHI-DirectX12/CMakeLists.txt index 5e465df6..5278e2c3 100644 --- a/Engine/Source/RHI-DirectX12/CMakeLists.txt +++ b/Engine/Source/RHI-DirectX12/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME RHI-DirectX12 TYPE SHARED SRC ${SOURCES} diff --git a/Engine/Source/RHI-Dummy/CMakeLists.txt b/Engine/Source/RHI-Dummy/CMakeLists.txt index ce75d82e..4527131b 100644 --- a/Engine/Source/RHI-Dummy/CMakeLists.txt +++ b/Engine/Source/RHI-Dummy/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME RHI-Dummy TYPE SHARED SRC ${SOURCES} diff --git a/Engine/Source/RHI-Vulkan/CMakeLists.txt b/Engine/Source/RHI-Vulkan/CMakeLists.txt index 19ba5a95..a76ac464 100644 --- a/Engine/Source/RHI-Vulkan/CMakeLists.txt +++ b/Engine/Source/RHI-Vulkan/CMakeLists.txt @@ -10,7 +10,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") "-framework CoreFoundation") endif() -AddLibrary( +exp_add_library( NAME RHI-Vulkan TYPE SHARED SRC ${SOURCES} ${PLATFORM_SOURCES} diff --git a/Engine/Source/RHI/CMakeLists.txt b/Engine/Source/RHI/CMakeLists.txt index f3a79a08..77c3b61d 100644 --- a/Engine/Source/RHI/CMakeLists.txt +++ b/Engine/Source/RHI/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME RHI TYPE STATIC SRC ${SOURCES} diff --git a/Engine/Source/Render/CMakeLists.txt b/Engine/Source/Render/CMakeLists.txt index 3efbf662..b0689bc1 100644 --- a/Engine/Source/Render/CMakeLists.txt +++ b/Engine/Source/Render/CMakeLists.txt @@ -3,7 +3,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") endif() file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Render.Static TYPE STATIC SRC ${SOURCES} @@ -12,7 +12,7 @@ AddLibrary( ) file(GLOB SHARED_SOURCES SharedSrc/*.cpp) -AddLibrary( +exp_add_library( NAME Render TYPE SHARED SRC ${SHARED_SOURCES} @@ -20,7 +20,7 @@ AddLibrary( ) file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( +exp_add_test( NAME Render.Test SRC ${TEST_SOURCES} LIB RHI Render.Static diff --git a/Engine/Source/Runtime/CMakeLists.txt b/Engine/Source/Runtime/CMakeLists.txt index 3e127d5b..5133a8bc 100644 --- a/Engine/Source/Runtime/CMakeLists.txt +++ b/Engine/Source/Runtime/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB_RECURSE SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME Runtime TYPE SHARED SRC ${SOURCES} @@ -9,7 +9,7 @@ AddLibrary( ) file(GLOB TEST_SOURCES Test/*.cpp) -AddTest( +exp_add_test( NAME Runtime.Test SRC ${TEST_SOURCES} LIB Runtime diff --git a/Engine/Source/Test/CMakeLists.txt b/Engine/Source/Test/CMakeLists.txt index e73100e2..64d14628 100644 --- a/Engine/Source/Test/CMakeLists.txt +++ b/Engine/Source/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -AddLibrary( +exp_add_library( NAME Test TYPE STATIC SRC Src/Main.cpp diff --git a/Sample/CMakeLists.txt b/Sample/CMakeLists.txt index 5ddd74db..146d2da1 100644 --- a/Sample/CMakeLists.txt +++ b/Sample/CMakeLists.txt @@ -1,4 +1,4 @@ -function(AddSample) +function(add_sample) cmake_parse_arguments(PARAMS "" "NAME" "SRC;INC;SHADER;IMAGE;MODEL" ${ARGN}) if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") @@ -24,7 +24,7 @@ function(AddSample) list(APPEND PATHS "${CMAKE_SOURCE_DIR}/Engine/Shader/Platform.esh->../Test/Sample/ShaderInclude/Platform.esh") - AddExecutable( + exp_add_executable( SAMPLE NAME ${PARAMS_NAME} SRC ${PARAMS_SRC} @@ -44,7 +44,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") endif() file(GLOB SOURCES Base/*.cpp) -Addlibrary( +exp_add_library( NAME Sample-Base SRC ${SOURCES} PUBLIC_INC Base @@ -53,7 +53,7 @@ Addlibrary( ) file(GLOB SOURCES RHI-Triangle/*.cpp) -AddSample( +add_sample( NAME RHISample-Triangle SRC ${SOURCES} INC RHI-Triangle @@ -61,7 +61,7 @@ AddSample( ) file(GLOB SOURCES RHI-TexSampling/*.cpp) -AddSample( +add_sample( NAME RHISample-TexSampling SRC ${SOURCES} INC RHI-TexSampling @@ -70,7 +70,7 @@ AddSample( ) file(GLOB SOURCES RHI-SSAO/*.cpp) -AddSample( +add_sample( NAME RHISample-SSAO SRC ${SOURCES} INC RHI-SSAO @@ -84,14 +84,14 @@ AddSample( ) file(GLOB SOURCES RHI-ParallelCompute/*.cpp) -AddSample( +add_sample( NAME RHISample-ParallelCompute SRC ${SOURCES} SHADER RHI-ParallelCompute/Compute.esl ) file(GLOB SOURCES Rendering-Triangle/*.cpp) -AddSample( +add_sample( NAME RenderingSample-Triangle SRC ${SOURCES} INC Rendering-Triangle diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 5ca1ecbe..7a3559ea 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -1,5 +1,5 @@ # DirectX 12 Headers -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME DirectXHeaders PLATFORM Windows VERSION 1.4.9 @@ -9,7 +9,7 @@ Add3rdHeaderOnlyPackage( # VulkanSDK set(VULKAN_SDK_VERSION 1.3.296.0) -Add3rdBinaryPackage( +exp_add_3rd_binary_package( NAME VulkanSDK VERSION ${VULKAN_SDK_VERSION} HASH @@ -104,7 +104,7 @@ endif () # DXC # Windows uses standalone package, macOS uses lib in VulkanSDK -Add3rdBinaryPackage( +exp_add_3rd_binary_package( NAME dxc PLATFORM Windows VERSION 1.6.2112 @@ -115,14 +115,14 @@ Add3rdBinaryPackage( RUNTIME_DEP Windows $/bin/x64/dxcompiler.dll $/bin/x64/dxil.dll ) -Add3rdAliasPackage( +exp_add_3rd_alias_package( NAME dxc PLATFORM Darwin LIB dxcompiler ) # GLFW -Add3rdCMakeProject( +exp_add_3rd_cmake_package( NAME glfw PLATFORM All VERSION 4.0 @@ -134,7 +134,7 @@ Add3rdCMakeProject( ) # clipp -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME clipp PLATFORM All VERSION forked-f7cffbd61a7b64189d6573e8c3848d094c35168a @@ -143,7 +143,7 @@ Add3rdHeaderOnlyPackage( ) # DebugBreak -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME debugbreak PLATFORM All VERSION 1.0 @@ -152,7 +152,7 @@ Add3rdHeaderOnlyPackage( ) # LLVM-Clang -Add3rdBinaryPackage( +exp_add_3rd_binary_package( NAME llvm-clang ARCH VERSION @@ -172,7 +172,7 @@ Add3rdBinaryPackage( ) # Google Test -Add3rdCMakeProject( +exp_add_3rd_cmake_package( NAME googletest PLATFORM All VERSION 1.11.0 @@ -184,7 +184,7 @@ Add3rdCMakeProject( ) # TaskFlow -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME taskflow PLATFORM All VERSION 3.4.0 @@ -193,7 +193,7 @@ Add3rdHeaderOnlyPackage( ) # CityHash -Add3rdCMakeProject( +exp_add_3rd_cmake_package( NAME cityhash PLATFORM All VERSION forked-2f248cfbf88d0895d069258e4971b5f2fc3a9f19 @@ -204,7 +204,7 @@ Add3rdCMakeProject( ) # stb-image -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME stb PLATFORM All VERSION master-8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 @@ -213,7 +213,7 @@ Add3rdHeaderOnlyPackage( ) # spirv-cross -Add3rdCMakeProject( +exp_add_3rd_cmake_package( NAME spirv-cross PLATFORM All VERSION 1.3.243.0 @@ -227,7 +227,7 @@ Add3rdCMakeProject( ) # assimp -Add3rdCMakeProject( +exp_add_3rd_cmake_package( NAME assimp-lib PLATFORM All VERSION 5.2.5 @@ -243,7 +243,7 @@ Add3rdCMakeProject( ) # vma -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME VulkanMemoryAllocator PLATFORM All VERSION 3.0.1 @@ -253,7 +253,7 @@ Add3rdHeaderOnlyPackage( # Qt6 set(QT_VERSION "6.9.1" CACHE STRING "" FORCE) -Setup3rdPackage( +exp_setup_3rd_package( NAME Qt VERSION ${QT_VERSION} HASH @@ -270,7 +270,7 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") endif () # rapidjson -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME rapidjson PLATFORM All VERSION d621dc9 @@ -280,7 +280,7 @@ Add3rdHeaderOnlyPackage( # Node.js set(NODEJS_VERSION "22.18.0" CACHE STRING "" FORCE) -Add3rdBinaryPackage( +exp_add_3rd_binary_package( NAME Nodejs VERSION ${NODEJS_VERSION} HASH @@ -290,11 +290,10 @@ Add3rdBinaryPackage( # cpp-httplib set(CPP_HTTP_LIB_VERSION "0.24.0") -Add3rdHeaderOnlyPackage( +exp_add_3rd_header_only_package( NAME cpp-httplib PLATFORM All VERSION 0.24.0 HASH a0320b106f4a8f945ec2556e62fffab05b068f2ddfff99c6a367b2e16c14bde1 INCLUDE $ ) -set(CPP_HTTP_LIB_SOURCE_DIR ${3RD_SOURCE_DIR}/cpp-httplib-All-${CPP_HTTP_LIB_VERSION} CACHE STRING "" FORCE) diff --git a/Tool/MirrorTool/CMakeLists.txt b/Tool/MirrorTool/CMakeLists.txt index 4d83a65b..fcd5a331 100644 --- a/Tool/MirrorTool/CMakeLists.txt +++ b/Tool/MirrorTool/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB SOURCES Src/*.cpp) -AddLibrary( +exp_add_library( NAME MirrorTool.Static SRC ${SOURCES} PUBLIC_INC Include @@ -7,14 +7,14 @@ AddLibrary( ) file(GLOB EXE_SOURCES ExeSrc/*.cpp) -AddExecutable( +exp_add_executable( NAME MirrorTool SRC ${EXE_SOURCES} INC Include LIB MirrorTool.Static ) -AddTest( +exp_add_test( NAME MirrorTool.Test SRC Test/Main.cpp INC Include From 5d6a93f99f9a7db80d5733487ebe18a3c20df671 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Mon, 18 Aug 2025 21:39:14 +0800 Subject: [PATCH 03/12] feat: project hub update --- Editor/CMakeLists.txt | 7 + .../EngineSerialization.h} | 0 Editor/Include/Editor/Qt/JsonSerialization.h | 1536 +++++++++++++++++ Editor/Include/Editor/Qt/MirrorTemplateView.h | 375 ++++ Editor/Include/Editor/Widget/Editor.h | 4 +- Editor/Include/Editor/Widget/ProjectHub.h | 37 +- .../ProjectTemplates/2D/CMakeLists.txt | 5 + .../ProjectTemplates/3D/CMakeLists.txt | 5 + Editor/Src/Main.cpp | 2 +- Editor/Src/Qt/MirrorTemplateView.cpp | 141 ++ Editor/Src/QtGlue/Serialization.cpp | 5 - Editor/Src/Widget/Editor.cpp | 2 +- Editor/Src/Widget/ProjectHub.cpp | 50 +- Editor/Web/src/pages/project-hub.tsx | 126 +- Editor/Web/src/qwebchannel.d.ts | 2 +- .../Source/Common/Include/Common/FileSystem.h | 1 + .../Source/Common/Include/Common/Math/Math.h | 18 + .../Common/Include/Common/Serialization.h | 36 +- Engine/Source/Common/Include/Common/Utility.h | 19 + Engine/Source/Common/Src/FileSystem.cpp | 6 + Engine/Source/Mirror/Include/Mirror/Mirror.h | 611 ++++++- Engine/Source/Mirror/Src/Mirror.cpp | 206 ++- Engine/Source/Mirror/Test/AnyTest.cpp | 8 +- 23 files changed, 3052 insertions(+), 150 deletions(-) rename Editor/Include/Editor/{QtGlue/Serialization.h => Qt/EngineSerialization.h} (100%) create mode 100644 Editor/Include/Editor/Qt/JsonSerialization.h create mode 100644 Editor/Include/Editor/Qt/MirrorTemplateView.h create mode 100644 Editor/Resource/ProjectTemplates/2D/CMakeLists.txt create mode 100644 Editor/Resource/ProjectTemplates/3D/CMakeLists.txt create mode 100644 Editor/Src/Qt/MirrorTemplateView.cpp delete mode 100644 Editor/Src/QtGlue/Serialization.cpp create mode 100644 Engine/Source/Common/Include/Common/Math/Math.h diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 6e869fa7..05b9e282 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -110,6 +110,13 @@ foreach (SHADER ${SHADERS}) list(APPEND EDITOR_RESOURCES ${SHADER}->${COPY_DST}) endforeach () +file(GLOB_RECURSE RESOURCES Resource/*) +foreach (RESOURCE ${RESOURCES}) + get_filename_component(RESOURCE_ABSOLUTE ${RESOURCE} ABSOLUTE) + string(REPLACE ${CMAKE_CURRENT_SOURCE_DIR}/Resource ../Resource/Editor COPY_DST ${RESOURCE_ABSOLUTE}) + list(APPEND EDITOR_RESOURCES ${RESOURCE}->${COPY_DST}) +endforeach () + exp_add_resources_copy_command( NAME Editor RES ${EDITOR_RESOURCES} diff --git a/Editor/Include/Editor/QtGlue/Serialization.h b/Editor/Include/Editor/Qt/EngineSerialization.h similarity index 100% rename from Editor/Include/Editor/QtGlue/Serialization.h rename to Editor/Include/Editor/Qt/EngineSerialization.h diff --git a/Editor/Include/Editor/Qt/JsonSerialization.h b/Editor/Include/Editor/Qt/JsonSerialization.h new file mode 100644 index 00000000..e72f2020 --- /dev/null +++ b/Editor/Include/Editor/Qt/JsonSerialization.h @@ -0,0 +1,1536 @@ +// +// Created by Kindem on 2025/8/18. +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// TODO +#pragma optimize("", off) + +namespace Editor { + template struct QtJsonSerializer {}; + template concept QtJsonSerializable = requires( + const T& inValue, T& outValue, + const QJsonValue& inJsonValue, QJsonValue& outJsonValue) + { + QtJsonSerializer::QtJsonSerialize(outJsonValue, inValue); + QtJsonSerializer::QtJsonDeserialize(inJsonValue, outValue); + }; + + template void QtJsonSerialize(QJsonValue& outJsonValue, const T& inValue); + template void QtJsonDeserialize(const QJsonValue& inJsonValue, T& outValue); +} + +namespace Editor { + template + void QtJsonSerialize(QJsonValue& outJsonValue, const T& inValue) + { + if constexpr (QtJsonSerializable) { + QtJsonSerializer::QtJsonSerialize(outJsonValue, inValue); + } else { + QuickFailWithReason("your type is not support json serialization"); + } + } + + template + void QtJsonDeserialize(const QJsonValue& inJsonValue, T& outValue) + { + if constexpr (QtJsonSerializable) { + QtJsonSerializer::QtJsonDeserialize(inJsonValue, outValue); + } else { + QuickFailWithReason("your type is not support json serialization"); + } + } + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, bool inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, bool& outValue) + { + if (!inJsonValue.isBool()) { + return; + } + outValue = inJsonValue.toBool(); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, int8_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, int8_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInt()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, uint8_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, uint8_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInt()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, int16_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, int16_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInt()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, uint16_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, uint16_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInt()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, int32_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, int32_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = inJsonValue.toInt(); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, uint32_t inValue) + { + outJsonValue = static_cast(inValue); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, uint32_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInteger()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, int64_t inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, int64_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = inJsonValue.toInteger(); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, uint64_t inValue) + { + outJsonValue = static_cast(inValue); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, uint64_t& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toInteger()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, float inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, float& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = static_cast(inJsonValue.toDouble()); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, double inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, double& outValue) + { + if (!inJsonValue.isDouble()) { + return; + } + outValue = inJsonValue.toDouble(); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::string& inValue) + { + outJsonValue = QString::fromStdString(inValue); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::string& outValue) + { + if (!inJsonValue.isString()) { + return; + } + outValue = inJsonValue.toString().toStdString(); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::wstring& inValue) + { + outJsonValue = QString::fromStdWString(inValue); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::wstring& outValue) + { + if (!inJsonValue.isString()) { + return; + } + outValue = inJsonValue.toString().toStdWString(); + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::optional& inValue) + { + if (inValue.has_value()) { + QtJsonSerializer::QtJsonSerialize(outJsonValue, inValue.value()); + } else { + outJsonValue = QJsonValue::Null; + } + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::optional& outValue) + { + outValue.reset(); + if (inJsonValue.isNull()) { + return; + } + T& outValueRef = outValue.emplace(); + QtJsonSerializer::QtJsonDeserialize(inJsonValue, outValueRef); + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::pair& inValue) + { + QJsonValue jsonKey; + QtJsonSerializer::QtJsonSerialize(jsonKey, inValue.first); + + QJsonValue jsonValue; + QtJsonSerializer::QtJsonSerialize(jsonValue, inValue.second); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + outJsonValue = std::move(jsonObject); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::pair& outValue) + { + if (!inJsonValue.isObject()) { + return; + } + const QJsonObject jsonObject = inJsonValue.toObject(); + if (jsonObject.contains("key")) { + const QJsonValue jsonKey = jsonObject["key"]; + QtJsonSerializer::QtJsonDeserialize(jsonKey, outValue.first); + } + if (jsonObject.contains("value")) { + const QJsonValue jsonValue = jsonObject["value"]; + QtJsonSerializer::QtJsonDeserialize(jsonValue, outValue.second); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::array& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::array& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != N) { + return; + } + for (auto i = 0; i < N; i++) { + QtJsonSerializer::QtJsonDeserialize(jsonArray[i], outValue[i]); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::vector& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::vector& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplaceback(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::list& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::list& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplace_back(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::unordered_set& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::unordered_set& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplace(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::set& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::set& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplace(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::unordered_map& inValue) + { + QJsonArray jsonArray; + for (const auto& pair : inValue) { + QJsonValue jsonPair; + QtJsonSerializer>::QtJsonSerialize(jsonPair, pair); + jsonArray.append(jsonPair); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::unordered_map& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonPair : jsonArray) { + std::pair pair; + QtJsonSerializer>::QtJsonSerialize(jsonPair, pair); + outValue.emplace(std::move(pair)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::map& inValue) + { + QJsonArray jsonArray; + for (const auto& pair : inValue) { + QJsonValue jsonPair; + QtJsonSerializer>::QtJsonSerialize(jsonPair, pair); + jsonArray.append(jsonPair); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::map& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonPair : jsonArray) { + std::pair pair; + QtJsonSerializer>::QtJsonSerialize(jsonPair, pair); + outValue.emplace(std::move(pair)); + } + } + }; + + template + struct QtJsonSerializer> { + template + static void QtJsonSerializeInternal(QJsonObject& outJsonObject, const std::tuple& inValue, std::index_sequence) + { + (void) std::initializer_list { ([&]() -> void { + const auto key = std::to_string(I); + + QJsonValue jsonValue; + QtJsonSerializer::QtJsonSerialize(jsonValue, std::get(inValue)); + + outJsonObject[QString::fromStdString(key)] = jsonValue; + }(), 0)... }; + } + + template + static void QtJsonDeserializeInternal(const QJsonObject& inJsonObject, std::tuple& outValue, std::index_sequence) + { + (void) std::initializer_list { ([&]() -> void { + const auto key = std::to_string(I); + const QJsonValue jsonValue = inJsonObject[key]; + if (jsonValue.isNull()) { + return; + } + QtJsonSerializer::QtJsonDeserialize(jsonValue, std::get(outValue)); + }(), 0)... }; + } + + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::tuple& inValue) + { + QJsonObject jsonObject; + QtJsonSerializeInternal(jsonObject, inValue, std::make_index_sequence {}); + outJsonValue = std::move(jsonObject); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::tuple& outValue) + { + outValue = {}; + if (!inJsonValue.isObject()) { + return; + } + QtJsonDeserializeInternal(inJsonValue.toObject(), outValue, std::make_index_sequence {}); + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const std::variant& inValue) + { + QJsonValue jsonType; + QtJsonSerializer::QtJsonSerialize(jsonType, inValue.index()); + + QJsonValue jsonContent; + std::visit([&](T0&& v) -> void { + QtJsonSerializer>::QtJsonSerialize(jsonContent, v); + }, inValue); + + QJsonObject jsonObject; + jsonObject["type"] = jsonType; + jsonObject["content"] = jsonContent; + outJsonValue = std::move(jsonObject); + } + + template + static void QtJsonDeserializeInternal(const QJsonValue& inContentJsonValue, std::variant& outValue, size_t inAspectIndex, std::index_sequence) + { + (void) std::initializer_list { ([&]() -> void { + if (I != inAspectIndex) { + return; + } + + T temp; + QtJsonSerializer::QtJsonDeserialize(inContentJsonValue, temp); + outValue = std::move(temp); + }(), 0)... }; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, std::variant& outValue) + { + if (!inJsonValue.isObject()) { + return; + } + + const QJsonObject jsonObject = inJsonValue.toObject(); + if (!jsonObject.contains("type") || !jsonObject.contains("content")) { + return; + } + const QJsonValue jsonType = jsonObject["type"]; + const QJsonValue jsonContent = jsonObject["content"]; + + uint64_t aspectIndex; + QtJsonSerializer::QtJsonDeserialize(jsonType, aspectIndex); + QtJsonDeserializeInternal(jsonContent, outValue, aspectIndex, std::make_index_sequence {}); + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const Common::Vec& inValue) + { + QJsonArray jsonArray; + for (auto i = 0; i < L; i++) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, inValue[i]); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, Common::Vec& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != L) { + return; + } + for (auto i = 0; i < L; i++) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonDeserialize(jsonElement, jsonArray[i]); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& jsonValue, const Common::Mat& inValue) + { + QJsonArray jsonArray; + for (auto i = 0; i < R; i++) { + for (auto j = 0; j < C; j++) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, inValue.At(i, j)); + jsonArray.append(jsonElement); + } + } + jsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& jsonValue, Common::Mat& outValue) + { + if (!jsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = jsonValue.toArray(); + if (jsonArray.size() != R * C) { + return; + } + for (auto i = 0; i < jsonArray.size(); i++) { + auto row = i / C; + auto col = i % C; + QtJsonSerializer::QtJsonDeserialize(jsonArray[i], outValue.At(row, col)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const Common::Quaternion& inValue) + { + QJsonValue jsonW; + QtJsonSerializer::QtJsonSerialize(jsonW, inValue.w); + + QJsonValue jsonX; + QtJsonSerializer::QtJsonSerialize(jsonX, inValue.x); + + QJsonValue jsonY; + QtJsonSerializer::QtJsonSerialize(jsonY, inValue.y); + + QJsonValue jsonZ; + QtJsonSerializer::QtJsonSerialize(jsonZ, inValue.z); + + QJsonArray jsonArray; + jsonArray.append(jsonX); + jsonArray.append(jsonY); + jsonArray.append(jsonZ); + jsonArray.append(jsonW); + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, Common::Quaternion& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != 4) { + return; + } + + const QJsonValue jsonX = jsonArray[0]; + QtJsonSerializer::QtJsonDeserialize(jsonX, outValue.x); + + const QJsonValue jsonY = jsonArray[1]; + QtJsonSerializer::QtJsonDeserialize(jsonY, outValue.y); + + const QJsonValue jsonZ = jsonArray[2]; + QtJsonSerializer::QtJsonDeserialize(jsonZ, outValue.z); + + const QJsonValue jsonW = jsonArray[3]; + QtJsonSerializer::QtJsonDeserialize(jsonW, outValue.w); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, const Common::Color& inValue) + { + QJsonValue jsonR; + QtJsonSerializer::QtJsonSerialize(jsonR, inValue.r); + + QJsonValue jsonG; + QtJsonSerializer::QtJsonSerialize(jsonG, inValue.g); + + QJsonValue jsonB; + QtJsonSerializer::QtJsonSerialize(jsonB, inValue.b); + + QJsonValue jsonA; + QtJsonSerializer::QtJsonSerialize(jsonA, inValue.a); + + QJsonArray jsonArray; + jsonArray.append(jsonR); + jsonArray.append(jsonG); + jsonArray.append(jsonB); + jsonArray.append(jsonA); + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, Common::Color& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != 4) { + return; + } + + const QJsonValue jsonR = jsonArray[0]; + QtJsonSerializer::QtJsonDeserialize(jsonR, outValue.r); + + const QJsonValue jsonG = jsonArray[1]; + QtJsonSerializer::QtJsonDeserialize(jsonG, outValue.g); + + const QJsonValue jsonB = jsonArray[2]; + QtJsonSerializer::QtJsonDeserialize(jsonB, outValue.b); + + const QJsonValue jsonA = jsonArray[3]; + QtJsonSerializer::QtJsonDeserialize(jsonA, outValue.a); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, const Common::LinearColor& inValue) + { + QJsonValue jsonR; + QtJsonSerializer::QtJsonSerialize(jsonR, inValue.r); + + QJsonValue jsonG; + QtJsonSerializer::QtJsonSerialize(jsonG, inValue.g); + + QJsonValue jsonB; + QtJsonSerializer::QtJsonSerialize(jsonB, inValue.b); + + QJsonValue jsonA; + QtJsonSerializer::QtJsonSerialize(jsonA, inValue.a); + + QJsonArray jsonArray; + jsonArray.append(jsonR); + jsonArray.append(jsonG); + jsonArray.append(jsonB); + jsonArray.append(jsonA); + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, Common::LinearColor& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != 4) { + return; + } + + const QJsonValue jsonR = jsonArray[0]; + QtJsonSerializer::QtJsonDeserialize(jsonR, outValue.r); + + const QJsonValue jsonG = jsonArray[1]; + QtJsonSerializer::QtJsonDeserialize(jsonG, outValue.g); + + const QJsonValue jsonB = jsonArray[2]; + QtJsonSerializer::QtJsonDeserialize(jsonB, outValue.b); + + const QJsonValue jsonA = jsonArray[3]; + QtJsonSerializer::QtJsonDeserialize(jsonA, outValue.a); + } + }; + + template <> + struct QtJsonSerializer { + static void QtJsonSerialize(QJsonValue& outJsonValue, const QString& inValue) + { + outJsonValue = inValue; + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, QString& outValue) + { + if (!inJsonValue.isString()) { + return; + } + outValue = inJsonValue.toString(); + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const QList& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.push_back(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, QList& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplaceBack(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const QSet& inValue) + { + QJsonArray jsonArray; + for (const auto& element : inValue) { + QJsonValue jsonElement; + QtJsonSerializer::QtJsonSerialize(jsonElement, element); + jsonArray.push_back(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, QSet& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + outValue.reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + T element; + QtJsonSerializer::QtJsonDeserialize(jsonElement, element); + outValue.emplaceBack(std::move(element)); + } + } + }; + + template + struct QtJsonSerializer> { + static void QtJsonSerialize(QJsonValue& outJsonValue, const QMap& inValue) + { + QJsonArray jsonArray; + for (const auto& [key, value] : inValue) { + QJsonValue jsonKey; + QtJsonSerializer::QtJsonSerialize(jsonKey, key); + + QJsonValue jsonValue; + QtJsonSerializer::QtJsonSerialize(jsonValue, value); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + jsonArray.append(std::move(jsonObject)); + } + outJsonValue = std::move(jsonArray); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, QMap& outValue) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + outValue.clear(); + for (const auto& jsonElement : jsonArray) { + if (!jsonElement.isObject()) { + continue; + } + const QJsonObject jsonObject = jsonElement.toObject(); + + K key; + if (jsonObject.contains("key")) { + const QJsonValue jsonKey = jsonObject["key"]; + QtJsonSerializer::QtJsonDeserialize(jsonKey, key); + } + + V value; + if (jsonObject.contains("value")) { + const QJsonValue jsonValue = jsonObject["value"]; + QtJsonSerializer::QtJsonDeserialize(jsonValue, value); + } + + outValue.emplace(std::move(key), std::move(value)); + } + } + }; + + template + struct QtJsonSerializer { + static void QtJsonSerializeDyn(QJsonObject& outJsonObject, const Mirror::Class& inClass, const Mirror::Argument& inValue) + { + const auto* baseClass = inClass.GetBaseClass(); + const auto& memberVariables = inClass.GetMemberVariables(); + const auto defaultObject = inClass.GetDefaultObject(); + + if (baseClass != nullptr) { + QJsonObject baseContentJson; + QtJsonSerializeDyn(baseContentJson, *baseClass, inValue); + outJsonObject["_base"] = std::move(baseContentJson); + } + + for (const auto& memberVariable : memberVariables | std::views::values) { + if (memberVariable.IsTransient()) { + continue; + } + + const bool sameAsDefault = defaultObject.Empty() || !memberVariable.GetTypeInfo()->equalComparable + ? false + : memberVariable.GetDyn(inValue) == memberVariable.GetDyn(defaultObject); + + if (sameAsDefault) { + continue; + } + QJsonValue memberContentJson; + Mirror::Any memberRef = memberVariable.GetDyn(inValue); + SerializeValueDyn(memberContentJson, memberRef); + outJsonObject[QString::fromStdString(memberVariable.GetName())] = memberContentJson; + } + } + + static void QtJsonDeserializeDyn(const QJsonObject& inJsonObject, const Mirror::Class& inClass, const Mirror::Argument& outValue) + { + const auto* baseClass = inClass.GetBaseClass(); + const auto defaultObject = inClass.GetDefaultObject(); + + if (inJsonObject.contains("_base")) { + if (const QJsonValue baseContentJson = inJsonObject["_base"]; + baseClass != nullptr && baseContentJson.isObject()) { + QtJsonDeserializeDyn(baseContentJson.toObject(), *baseClass, outValue); + } + } + + for (const auto& memberVariable : inClass.GetMemberVariables() | std::views::values) { + const auto& memberName = memberVariable.GetName(); + if (const QJsonValue memberContentJson = inJsonObject[QString::fromStdString(memberName)]; + !memberContentJson.isNull()) { + DeserializeValueDyn(memberContentJson, memberVariable.GetDyn(outValue)); + } else { + if (!defaultObject.Empty()) { + memberVariable.SetDyn(outValue, memberVariable.GetDyn(defaultObject)); + } + } + } + } + + static void QtJsonSerialize(QJsonValue& outJsonValue, const T& inValue) + { + QJsonObject jsonObject; + QtJsonSerializeDyn(jsonObject, Mirror::Class::Get(), Mirror::ForwardAsArg(inValue)); + outJsonValue = std::move(jsonObject); + } + + static void QtJsonDeserialize(const QJsonValue& inJsonValue, T& outValue) + { + if (inJsonValue.isNull()) { + return; + } + QtJsonDeserializeDyn(inJsonValue.toObject(), Mirror::Class::Get(), Mirror::ForwardAsArg(outValue)); + } + + private: + using SupportedSimpleTypes = std::tuple< + bool, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float, double, std::string, std::wstring, + Common::FVec2, Common::FVec3, Common::FVec4, Common::FMat4x4, Common::FQuat, Common::Color, Common::LinearColor, + QString + >; + + using SupportedTemplateViews = std::tuple< + Common::Wrap, Common::Wrap, Common::Wrap, Common::Wrap, + Common::Wrap, Common::Wrap, Common::Wrap, Common::Wrap, + Common::Wrap, Common::Wrap, Common::Wrap, Common::Wrap, Common::Wrap + >; + + static auto BuildSimpleTypeDynSerializers() + { + std::unordered_map> result; + Common::TupleTypeTraverser::Each([&](T0&&) -> void { + using RawType = std::decay_t; + result.emplace(Mirror::GetTypeId(), [](QJsonValue& outJsonValue, const Mirror::Any& inRef) -> void { + QtJsonSerializer::QtJsonSerialize(outJsonValue, inRef.As()); + }); + }); + return result; + } + + static auto BuildSimpleTypeDynDeserializers() + { + std::unordered_map> result; + Common::TupleTypeTraverser::Each([&](T0&&) -> void { + using RawType = std::decay_t; + result.emplace(Mirror::GetTypeId(), [](const QJsonValue& inJsonValue, const Mirror::Any& outRef) -> void { + QtJsonSerializer::QtJsonDeserialize(inJsonValue, outRef.As()); + }); + }); + return result; + } + + static auto BuildTemplateViewDynSerializers() + { + std::unordered_map> result; + Common::TupleTypeTraverser::Each([&](T0&&) -> void { + using RawType = typename std::decay_t::RawType; + result.emplace(RawType::id, [](QJsonValue& outJsonValue, const Mirror::Any& inRef) -> void { + const RawType view(inRef); + SerializeDynWithView(outJsonValue, view); + }); + }); + return result; + } + + static auto BuildTemplateViewDynDeserializers() + { + std::unordered_map> result; + Common::TupleTypeTraverser::Each([&](T0&&) -> void { + using RawType = typename std::decay_t::RawType; + result.emplace(RawType::id, [](const QJsonValue& inJsonValue, const Mirror::Any& inRef) -> void { + const RawType view(inRef); + DeserializeDynWithView(inJsonValue, view); + }); + }); + return result; + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdOptionalView& inView) + { + if (inView.HasValue()) { + SerializeValueDyn(outJsonValue, inView.ConstValue()); + } else { + outJsonValue = QJsonValue::Null; + } + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdOptionalView& inView) + { + inView.Reset(); + if (inJsonValue.isNull()) { + return; + } + const Mirror::Any newValueRef = inView.EmplaceDefault(); + DeserializeValueDyn(inJsonValue, newValueRef); + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdPairView& inView) + { + QJsonValue jsonKey; + SerializeValueDyn(jsonKey, inView.ConstKey()); + + QJsonValue jsonValue; + SerializeValueDyn(jsonValue, inView.ConstValue()); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + outJsonValue = std::move(jsonValue); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdPairView& inView) + { + if (!inJsonValue.isObject()) { + return; + } + inView.Reset(); + const QJsonObject jsonObject = inJsonValue.toObject(); + if (jsonObject.contains("key")) { + const QJsonValue jsonKey = jsonObject["key"]; + DeserializeValueDyn(jsonKey, inView.Key()); + } + if (jsonObject.contains("value")) { + const QJsonValue jsonValue = jsonObject["value"]; + DeserializeValueDyn(jsonValue, inView.Value()); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdArrayView& inView) + { + QJsonArray jsonArray; + for (auto i = 0; i < inView.Size(); i++) { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, inView.ConstAt(i)); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdArrayView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + if (jsonArray.size() != inView.Size()) { + return; + } + for (auto i = 0; i < jsonArray.size(); i++) { + const QJsonValue jsonElement = jsonArray[i]; + DeserializeValueDyn(jsonElement, inView.At(i)); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdVectorView& inView) + { + QJsonArray jsonArray; + for (auto i = 0; i < inView.Size(); i++) { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, inView.ConstAt(i)); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdVectorView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + inView.Reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + DeserializeValueDyn(jsonElement, inView.EmplaceDefaultBack()); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdListView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& elementRef) -> void { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, elementRef); + jsonArray.append(jsonElement); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdListView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + for (const auto& jsonElement : jsonArray) { + DeserializeValueDyn(jsonElement, inView.EmplaceDefaultBack()); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdUnorderedSetView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& elementRef) -> void { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, elementRef); + jsonArray.append(jsonElement); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdUnorderedSetView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + inView.Reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + Mirror::Any element = inView.CreateElement(); + DeserializeValueDyn(jsonElement, element); + inView.Emplace(element); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdSetView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& elementRef) -> void { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, elementRef); + jsonArray.append(jsonElement); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdSetView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + for (const auto& jsonElement : jsonArray) { + Mirror::Any element = inView.CreateElement(); + DeserializeValueDyn(jsonElement, element); + inView.Emplace(element); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdUnorderedMapView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& inKey, const Mirror::Any& inValue) -> void { + QJsonValue jsonKey; + SerializeValueDyn(jsonKey, inKey); + + QJsonValue jsonValue; + SerializeValueDyn(jsonValue, inValue); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + jsonArray.append(jsonObject); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdUnorderedMapView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + inView.Reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + if (!jsonElement.isObject()) { + continue; + } + const QJsonObject jsonObject = jsonElement.toObject(); + Mirror::Any key = inView.CreateKey(); + if (jsonObject.contains("key")) { + QJsonValue jsonKey = jsonObject["key"]; + DeserializeValueDyn(jsonKey, key); + } + Mirror::Any value = inView.CreateValue(); + if (jsonObject.contains("value")) { + QJsonValue jsonValue = jsonObject["value"]; + DeserializeValueDyn(jsonValue, value); + } + inView.Emplace(key, value); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdMapView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& inKey, const Mirror::Any& inValue) -> void { + QJsonValue jsonKey; + SerializeValueDyn(jsonKey, inKey); + + QJsonValue jsonValue; + SerializeValueDyn(jsonValue, inValue); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + jsonArray.append(jsonObject); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdMapView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + for (const auto& jsonElement : jsonArray) { + if (!jsonElement.isObject()) { + continue; + } + const QJsonObject jsonObject = jsonElement.toObject(); + Mirror::Any key = inView.CreateKey(); + if (jsonObject.contains("key")) { + QJsonValue jsonKey = jsonObject["key"]; + DeserializeValueDyn(jsonKey, key); + } + Mirror::Any value = inView.CreateValue(); + if (jsonObject.contains("value")) { + QJsonValue jsonValue = jsonObject["value"]; + DeserializeValueDyn(jsonValue, value); + } + inView.Emplace(key, value); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdTupleView& inView) + { + QJsonObject jsonObject; + inView.ConstTraverse([&](const Mirror::Any& inElementRef, size_t inIndex) -> void { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, inElementRef); + jsonObject[QString::number(inIndex)] = jsonElement; + }); + outJsonValue = std::move(jsonObject); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdTupleView& inView) + { + if (!inJsonValue.isObject()) { + return; + } + const QJsonObject jsonObject = inJsonValue.toObject(); + for (const auto& key : jsonObject.keys()) { + const auto index = key.toUInt(); + const QJsonValue jsonElement = jsonObject[key]; + const Mirror::Any elementRef = inView.Get(index); + DeserializeValueDyn(jsonElement, elementRef); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const Mirror::StdVariantView& inView) + { + QJsonValue typeJson; + QtJsonSerializer::QtJsonSerialize(typeJson, inView.Index()); + + QJsonValue contentJson; + inView.Visit([&](const Mirror::Any& inValueRef) -> void { + SerializeValueDyn(contentJson, inValueRef); + }); + + QJsonObject jsonObject; + jsonObject["type"] = typeJson; + jsonObject["content"] = contentJson; + outJsonValue = std::move(jsonObject); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const Mirror::StdVariantView& inView) + { + if (!inJsonValue.isObject()) { + return; + } + const QJsonObject jsonObject = inJsonValue.toObject(); + if (!jsonObject.contains("type") || jsonObject.contains("content")) { + return; + } + + const QJsonValue typeJson = jsonObject["type"]; + const QJsonValue contentJson = jsonObject["content"]; + + uint64_t type; + QtJsonSerializer::QtJsonDeserialize(typeJson, type); + + Mirror::Any tempObj = inView.CreateElement(type); + DeserializeValueDyn(contentJson, tempObj); + + (void) inView.Emplace(type, tempObj); + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const QListMetaView& inView) + { + QJsonArray jsonArray; + for (auto i = 0; i < inView.Size(); i++) { + QJsonValue jsonElement; + SerializeValueDyn(jsonElement, inView.ConstAt(i)); + jsonArray.append(jsonElement); + } + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const QListMetaView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + inView.Reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + DeserializeValueDyn(jsonElement, inView.EmplaceDefaultBack()); + } + } + + static void SerializeDynWithView(QJsonValue& outJsonValue, const QMapMetaView& inView) + { + QJsonArray jsonArray; + inView.ConstTraverse([&](const Mirror::Any& inKey, const Mirror::Any& inValue) -> void { + QJsonValue jsonKey; + SerializeValueDyn(jsonKey, inKey); + + QJsonValue jsonValue; + SerializeValueDyn(jsonValue, inValue); + + QJsonObject jsonObject; + jsonObject["key"] = jsonKey; + jsonObject["value"] = jsonValue; + jsonArray.append(jsonObject); + }); + outJsonValue = std::move(jsonArray); + } + + static void DeserializeDynWithView(const QJsonValue& inJsonValue, const QMapMetaView& inView) + { + if (!inJsonValue.isArray()) { + return; + } + const QJsonArray jsonArray = inJsonValue.toArray(); + inView.Clear(); + inView.Reserve(jsonArray.size()); + for (const auto& jsonElement : jsonArray) { + if (!jsonElement.isObject()) { + continue; + } + const QJsonObject jsonObject = jsonElement.toObject(); + Mirror::Any key = inView.CreateKey(); + if (jsonObject.contains("key")) { + QJsonValue jsonKey = jsonObject["key"]; + DeserializeValueDyn(jsonKey, key); + } + Mirror::Any value = inView.CreateValue(); + if (jsonObject.contains("value")) { + QJsonValue jsonValue = jsonObject["value"]; + DeserializeValueDyn(jsonValue, value); + } + inView.Emplace(key, value); + } + } + + static void SerializeValueDyn(QJsonValue& outJsonValue, const Mirror::Any& inValueRef) + { + static auto simpleTypeDynSerializers = BuildSimpleTypeDynSerializers(); + static auto templateViewDynSerializers = BuildTemplateViewDynSerializers(); + + if (inValueRef.HasTemplateView()) { + const Mirror::TemplateViewId templateViewId = inValueRef.GetTemplateViewId(); + AssertWithReason(templateViewDynSerializers.contains(templateViewId), std::format("QtJsonSerializeValueDyn not support type {}", inValueRef.Type()->name)); + templateViewDynSerializers.at(templateViewId)(outJsonValue, inValueRef); + } else if (const Mirror::Class* clazz = inValueRef.GetDynamicClass(); clazz != nullptr) { + AssertWithReason(!inValueRef.Type()->isPointer, "QtJsonSerializeValueDyn not support meta object pointer"); + QJsonObject jsonObject; + QtJsonSerializeDyn(jsonObject, *clazz, inValueRef); + outJsonValue = std::move(jsonObject); + } else { + const Mirror::TypeId typeId = inValueRef.TypeId(); + AssertWithReason(simpleTypeDynSerializers.contains(typeId), std::format("QtJsonSerializeValueDyn not support type {}", inValueRef.Type()->name)); + simpleTypeDynSerializers.at(typeId)(outJsonValue, inValueRef); + } + } + + static void DeserializeValueDyn(const QJsonValue& inJsonValue, const Mirror::Any& outValueRef) + { + static auto simpleTypeDynDeserializers = BuildSimpleTypeDynDeserializers(); + static auto templateViewDynDeserializers = BuildTemplateViewDynDeserializers(); + + if (outValueRef.HasTemplateView()) { + const Mirror::TemplateViewId templateViewId = outValueRef.GetTemplateViewId(); + AssertWithReason(templateViewDynDeserializers.contains(templateViewId), std::format("QtJsonSerializeValueDyn not support type {}", outValueRef.Type()->name)); + templateViewDynDeserializers.at(templateViewId)(inJsonValue, outValueRef); + } else if (const Mirror::Class* clazz = outValueRef.GetDynamicClass(); clazz != nullptr) { + AssertWithReason(!outValueRef.Type()->isPointer, "QtJsonSerializeValueDyn not support meta object pointer"); + if (!inJsonValue.isObject()) { + return; + } + const QJsonObject jsonObject = inJsonValue.toObject(); + QtJsonDeserializeDyn(jsonObject, *clazz, outValueRef); + } else { + const Mirror::TypeId typeId = outValueRef.TypeId(); + AssertWithReason(simpleTypeDynDeserializers.contains(typeId), std::format("QtJsonSerializeValueDyn not support type {}", outValueRef.Type()->name)); + simpleTypeDynDeserializers.at(typeId)(inJsonValue, outValueRef); + } + } + }; +} diff --git a/Editor/Include/Editor/Qt/MirrorTemplateView.h b/Editor/Include/Editor/Qt/MirrorTemplateView.h new file mode 100644 index 00000000..79170e8c --- /dev/null +++ b/Editor/Include/Editor/Qt/MirrorTemplateView.h @@ -0,0 +1,375 @@ +// +// Created by Kindem on 2025/8/26. +// + +#pragma once + +#include +#include + +#include + +namespace Editor { + struct QListMetaViewRtti { + static constexpr Mirror::TemplateViewId id = Common::HashUtils::StrCrc32("Editor::QListMetaView"); + + using GetElementTypeFunc = const Mirror::TypeInfo*(); + using GetSizeFunc = size_t(const Mirror::Any&); + using ReserveFunc = void(const Mirror::Any&, size_t); + using ResizeFunc = void(const Mirror::Any&, size_t); + using ClearFunc = void(const Mirror::Any&); + using GetElementFunc = Mirror::Any(const Mirror::Any&, size_t); + using GetConstElementFunc = Mirror::Any(const Mirror::Any&, size_t); + using EmplaceBackFunc = Mirror::Any(const Mirror::Any&, const Mirror::Argument&); + using EmplaceDefaultBackFunc = Mirror::Any(const Mirror::Any&); + using RemoveFunc = void(const Mirror::Any&, size_t); + + template static const Mirror::TypeInfo* GetElementType(); + template static size_t GetSize(const Mirror::Any& inRef); + template static void Reserve(const Mirror::Any& inRef, size_t inSize); + template static void Resize(const Mirror::Any& inRef, size_t inSize); + template static void Clear(const Mirror::Any& inRef); + template static Mirror::Any GetElement(const Mirror::Any& inRef, size_t inIndex); + template static Mirror::Any GetConstElement(const Mirror::Any& inRef, size_t inIndex); + template static Mirror::Any EmplaceBack(const Mirror::Any& inRef, const Mirror::Argument& inTempObj); + template static Mirror::Any EmplaceDefaultBack(const Mirror::Any& inRef); + template static void Remove(const Mirror::Any& inRef, size_t inIndex); + + GetElementTypeFunc* getElementType; + GetSizeFunc* getSize; + ReserveFunc* reserve; + ResizeFunc* resize; + ClearFunc* clear; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + EmplaceBackFunc* emplaceBack; + EmplaceDefaultBackFunc* emplaceDefaultBack; + RemoveFunc* remove; + }; + + template + static constexpr QListMetaViewRtti qListMetaViewRttiImpl = { + &QListMetaViewRtti::GetElementType, + &QListMetaViewRtti::GetSize, + &QListMetaViewRtti::Reserve, + &QListMetaViewRtti::Resize, + &QListMetaViewRtti::Clear, + &QListMetaViewRtti::GetElement, + &QListMetaViewRtti::GetConstElement, + &QListMetaViewRtti::EmplaceBack, + &QListMetaViewRtti::EmplaceDefaultBack, + &QListMetaViewRtti::Remove + }; + + class QListMetaView { + public: + static constexpr Mirror::TemplateViewId id = QListMetaViewRtti::id; + + explicit QListMetaView(const Mirror::Any& inRef); + NonCopyable(QListMetaView) + NonMovable(QListMetaView) + + const Mirror::TypeInfo* ElementType() const; + size_t Size() const; + void Reserve(size_t inSize) const; + void Resize(size_t inSize) const; + void Clear() const; + Mirror::Any At(size_t inIndex) const; + Mirror::Any ConstAt(size_t inIndex) const; + Mirror::Any EmplaceBack(const Mirror::Argument& inTempObj) const; + Mirror::Any EmplaceDefaultBack() const; + void Remove(size_t inIndex) const; + + private: + Mirror::Any ref; + const QListMetaViewRtti* rtti; + }; + + struct QMapMetaViewRtti { + static constexpr Mirror::TemplateViewId id = Common::HashUtils::StrCrc32("Editor::QMapMetaView"); + + using GetKeyTypeFunc = const Mirror::TypeInfo*(); + using GetValueTypeFunc = const Mirror::TypeInfo*(); + using CreateKeyFunc = Mirror::Any(); + using CreateValueFunc = Mirror::Any(); + using GetSizeFunc = size_t(const Mirror::Any&); + using ReserveFunc = void(const Mirror::Any&, size_t); + using ClearFunc = void(const Mirror::Any&); + using GetOrAddFunc = Mirror::Any(const Mirror::Any&, const Mirror::Argument&); + using ConstAtFunc = Mirror::Any(const Mirror::Any&, const Mirror::Argument&); + using TraverseFunc = void(const Mirror::Any&, const std::function&); + using ConstTraverseFunc = void(const Mirror::Any&, const std::function&); + using ContainsFunc = bool(const Mirror::Any&, const Mirror::Argument&); + using EmplaceFunc = void(const Mirror::Any&, const Mirror::Argument&, const Mirror::Argument&); + using EraseFunc = void(const Mirror::Any&, const Mirror::Argument&); + + template static const Mirror::TypeInfo* GetKeyType(); + template static const Mirror::TypeInfo* GetValueType(); + template static Mirror::Any CreateKey(); + template static Mirror::Any CreateValue(); + template static size_t GetSize(const Mirror::Any& inRef); + template static void Reserve(const Mirror::Any& inRef, size_t inSize); + template static void Clear(const Mirror::Any& inRef); + template static Mirror::Any GetOrAdd(const Mirror::Any& inRef, const Mirror::Argument& inKey); + template static Mirror::Any ConstAt(const Mirror::Any& inRef, const Mirror::Argument& inKey); + template static void Traverse(const Mirror::Any& inRef, const std::function& inVisitor); + template static void ConstTraverse(const Mirror::Any& inRef, const std::function& inVisitor); + template static bool Contains(const Mirror::Any& inRef, const Mirror::Argument& inKey); + template static void Emplace(const Mirror::Any& inRef, const Mirror::Argument& inKey, const Mirror::Argument& inValue); + template static void Erase(const Mirror::Any& inRef, const Mirror::Argument& inKey); + + GetKeyTypeFunc* getKeyType; + GetValueTypeFunc* getValueType; + CreateKeyFunc* createKey; + CreateValueFunc* createValue; + GetSizeFunc* getSize; + ReserveFunc* reserve; + ClearFunc* clear; + GetOrAddFunc* getOrAdd; + ConstAtFunc* constAt; + TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; + ContainsFunc* contains; + EmplaceFunc* emplace; + EraseFunc* erase; + }; + + template + static constexpr QMapMetaViewRtti qMapMetaViewRttiImpl = { + &QMapMetaViewRtti::GetKeyType, + &QMapMetaViewRtti::GetValueType, + &QMapMetaViewRtti::CreateKey, + &QMapMetaViewRtti::CreateValue, + &QMapMetaViewRtti::GetSize, + &QMapMetaViewRtti::Reserve, + &QMapMetaViewRtti::Clear, + &QMapMetaViewRtti::GetOrAdd, + &QMapMetaViewRtti::ConstAt, + &QMapMetaViewRtti::Traverse, + &QMapMetaViewRtti::ConstTraverse, + &QMapMetaViewRtti::Contains, + &QMapMetaViewRtti::Emplace, + &QMapMetaViewRtti::Erase + }; + + class QMapMetaView { + public: + using PairTraverser = std::function; + static constexpr Mirror::TemplateViewId id = QMapMetaViewRtti::id; + + explicit QMapMetaView(const Mirror::Any& inRef); + NonCopyable(QMapMetaView) + NonMovable(QMapMetaView) + + const Mirror::TypeInfo* GetKeyType() const; + const Mirror::TypeInfo* GetValueType() const; + Mirror::Any CreateKey() const; + Mirror::Any CreateValue() const; + size_t GetSize() const; + void Reserve(size_t inSize) const; + void Clear() const; + Mirror::Any GetOrAdd(const Mirror::Argument& inKey) const; + Mirror::Any ConstAt(const Mirror::Argument& inKey) const; + void Traverse(const PairTraverser& inTraverser) const; + void ConstTraverse(const PairTraverser& inTraverser) const; + bool Contains(const Mirror::Argument& inKey) const; + void Emplace(const Mirror::Argument& inTempKey, const Mirror::Argument& inTempValue) const; + void Erase(const Mirror::Argument& inKey) const; + + private: + Mirror::Any ref; + const QMapMetaViewRtti* rtti; + }; +} // namespace Editor + +namespace Mirror { + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; +} + +namespace Editor { + template + const Mirror::TypeInfo* QListMetaViewRtti::GetElementType() + { + return Mirror::GetTypeInfo(); + } + + template + size_t QListMetaViewRtti::GetSize(const Mirror::Any& inRef) + { + return inRef.As&>().size(); + } + + template + void QListMetaViewRtti::Reserve(const Mirror::Any& inRef, size_t inSize) + { + inRef.As&>().reserve(inSize); + } + + template + void QListMetaViewRtti::Resize(const Mirror::Any& inRef, size_t inSize) + { + inRef.As&>().resize(inSize); + } + + template + void QListMetaViewRtti::Clear(const Mirror::Any& inRef) + { + inRef.As&>().clear(); + } + + template + Mirror::Any QListMetaViewRtti::GetElement(const Mirror::Any& inRef, size_t inIndex) + { + return std::ref(inRef.As&>()[inIndex]); + } + + template + Mirror::Any QListMetaViewRtti::GetConstElement(const Mirror::Any& inRef, size_t inIndex) + { + return std::ref(inRef.As&>()[inIndex]); + } + + template + Mirror::Any QListMetaViewRtti::EmplaceBack(const Mirror::Any& inRef, const Mirror::Argument& inTempObj) + { + return std::ref(inRef.As&>().emplaceBack(std::move(inTempObj.As()))); + } + + template + Mirror::Any QListMetaViewRtti::EmplaceDefaultBack(const Mirror::Any& inRef) + { + return std::ref(inRef.As&>().emplaceBack()); + } + + template + void QListMetaViewRtti::Remove(const Mirror::Any& inRef, size_t inIndex) + { + inRef.As&>().remove(inIndex); + } + + template + const Mirror::TypeInfo* QMapMetaViewRtti::GetKeyType() + { + return Mirror::GetTypeInfo(); + } + + template + const Mirror::TypeInfo* QMapMetaViewRtti::GetValueType() + { + return Mirror::GetTypeInfo(); + } + + template + Mirror::Any QMapMetaViewRtti::CreateKey() + { + return K(); + } + + template + Mirror::Any QMapMetaViewRtti::CreateValue() + { + return V(); + } + + template + size_t QMapMetaViewRtti::GetSize(const Mirror::Any& inRef) + { + return inRef.As&>().size(); + } + + template + void QMapMetaViewRtti::Reserve(const Mirror::Any& inRef, size_t inSize) + { + inRef.As&>().reserve(inSize); + } + + template + void QMapMetaViewRtti::Clear(const Mirror::Any& inRef) + { + inRef.As&>().clear(); + } + + template + Mirror::Any QMapMetaViewRtti::ConstAt(const Mirror::Any& inRef, const Mirror::Argument& inKey) + { + return inRef.As&>()[inKey]; + } + + template + Mirror::Any QMapMetaViewRtti::GetOrAdd(const Mirror::Any& inRef, const Mirror::Argument& inKey) + { + return inRef.As&>()[inKey]; + } + + template + void QMapMetaViewRtti::Traverse(const Mirror::Any& inRef, const std::function& inVisitor) + { + for (QMap& map = inRef.As&>(); + const auto& [key, value] : map) { + inVisitor(std::ref(key), std::ref(value)); + } + } + + template + void QMapMetaViewRtti::ConstTraverse(const Mirror::Any& inRef, const std::function& inVisitor) + { + for (const QMap& map = inRef.As&>(); + const auto& [key, value] : map) { + inVisitor(std::ref(key), std::ref(value)); + } + } + + template + bool QMapMetaViewRtti::Contains(const Mirror::Any& inRef, const Mirror::Argument& inKey) + { + return inRef.As&>().contains(inKey); + } + + template + void QMapMetaViewRtti::Emplace(const Mirror::Any& inRef, const Mirror::Argument& inKey, const Mirror::Argument& inValue) + { + inRef.As&>().emplace(inKey, inValue); + } + + template + void QMapMetaViewRtti::Erase(const Mirror::Any& inRef, const Mirror::Argument& inKey) + { + inRef.As&>().remove(inKey); + } +} // namespace Editor + +namespace Mirror { + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return Editor::QListMetaViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &Editor::qListMetaViewRttiImpl; + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return Editor::QMapMetaViewRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &Editor::qMapMetaViewRttiImpl; + } +} // namespace Mirror diff --git a/Editor/Include/Editor/Widget/Editor.h b/Editor/Include/Editor/Widget/Editor.h index 54281539..a11b6353 100644 --- a/Editor/Include/Editor/Widget/Editor.h +++ b/Editor/Include/Editor/Widget/Editor.h @@ -7,10 +7,10 @@ #include namespace Editor { - class Editor final : public QWidget { + class ExplosionEditor final : public QWidget { Q_OBJECT public: - Editor(); + ExplosionEditor(); }; } diff --git a/Editor/Include/Editor/Widget/ProjectHub.h b/Editor/Include/Editor/Widget/ProjectHub.h index 431460c6..4d49d39c 100644 --- a/Editor/Include/Editor/Widget/ProjectHub.h +++ b/Editor/Include/Editor/Widget/ProjectHub.h @@ -5,22 +5,49 @@ #pragma once #include +#include +#include +#include namespace Editor { class ProjectHub; - class ProjectHubBridge final : public QObject { + struct EClass() RecentProjectInfo { + EClassBody(RecentProjectInfo) + + EProperty() std::string name; + EProperty() std::string path; + }; + + struct EClass() ProjectTemplateInfo { + EClassBody(ProjectTemplateInfo) + + EProperty() std::string name; + EProperty() std::string path; + }; + + class ProjectHubBackend final : public QObject { Q_OBJECT - Q_PROPERTY(QString engineVersion MEMBER engineVersion CONSTANT) + Q_PROPERTY(QString engineVersion READ GetEngineVersion CONSTANT) + Q_PROPERTY(QJsonValue projectTemplates READ GetProjectTemplates CONSTANT) + Q_PROPERTY(QJsonValue recentProjects READ GetRecentProjects) public: - explicit ProjectHubBridge(ProjectHub* parent = nullptr); + explicit ProjectHubBackend(ProjectHub* parent = nullptr); + ~ProjectHubBackend() override; public Q_SLOTS: void CreateProject() const; private: - QString engineVersion; + QString GetEngineVersion() const; + QJsonValue GetProjectTemplates() const; + QJsonValue GetRecentProjects() const; + + Common::Path recentProjectsFile; + std::string engineVersion; + std::vector projectTemplates; + std::vector recentProjects; }; class ProjectHub final : public WebWidget { @@ -30,6 +57,6 @@ namespace Editor { explicit ProjectHub(QWidget* inParent = nullptr); private: - ProjectHubBridge* bridge; + ProjectHubBackend* backend; }; } diff --git a/Editor/Resource/ProjectTemplates/2D/CMakeLists.txt b/Editor/Resource/ProjectTemplates/2D/CMakeLists.txt new file mode 100644 index 00000000..91ab9c5e --- /dev/null +++ b/Editor/Resource/ProjectTemplates/2D/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.25) +project(%{projectName}%) + +include(ExternalProject) +include(GenerateExportHeader) diff --git a/Editor/Resource/ProjectTemplates/3D/CMakeLists.txt b/Editor/Resource/ProjectTemplates/3D/CMakeLists.txt new file mode 100644 index 00000000..91ab9c5e --- /dev/null +++ b/Editor/Resource/ProjectTemplates/3D/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.25) +project(%{projectName}%) + +include(ExternalProject) +include(GenerateExportHeader) diff --git a/Editor/Src/Main.cpp b/Editor/Src/Main.cpp index ce5eb0c5..3ff35e2d 100644 --- a/Editor/Src/Main.cpp +++ b/Editor/Src/Main.cpp @@ -99,7 +99,7 @@ static Common::UniquePtr CreateMainWidget(EditorApplicationModel inMode if (inModel == EditorApplicationModel::projectHub) { // NOLINT return new Editor::ProjectHub(); } - return new Editor::Editor(); + return new Editor::ExplosionEditor(); } int main(int argc, char* argv[]) diff --git a/Editor/Src/Qt/MirrorTemplateView.cpp b/Editor/Src/Qt/MirrorTemplateView.cpp new file mode 100644 index 00000000..573970db --- /dev/null +++ b/Editor/Src/Qt/MirrorTemplateView.cpp @@ -0,0 +1,141 @@ +// +// Created by Kindem on 2025/8/26. +// + +#include + +namespace Editor { + QListMetaView::QListMetaView(const Mirror::Any& inRef) + : ref(inRef) + { + Assert(inRef.IsRef() && ref.CanAsTemplateView()); + rtti = static_cast(ref.GetTemplateViewRtti()); + } + + const Mirror::TypeInfo* QListMetaView::ElementType() const + { + return rtti->getElementType(); + } + + size_t QListMetaView::Size() const + { + return rtti->getSize(ref); + } + + void QListMetaView::Reserve(size_t inSize) const + { + rtti->reserve(ref, inSize); + } + + void QListMetaView::Resize(size_t inSize) const + { + rtti->resize(ref, inSize); + } + + void QListMetaView::Clear() const + { + rtti->clear(ref); + } + + Mirror::Any QListMetaView::At(size_t inIndex) const + { + return rtti->getElement(ref, inIndex); + } + + Mirror::Any QListMetaView::ConstAt(size_t inIndex) const + { + return rtti->getConstElement(ref, inIndex); + } + + Mirror::Any QListMetaView::EmplaceBack(const Mirror::Argument& inTempObj) const + { + return rtti->emplaceBack(ref, inTempObj); + } + + Mirror::Any QListMetaView::EmplaceDefaultBack() const + { + return rtti->emplaceDefaultBack(ref); + } + + void QListMetaView::Remove(size_t inIndex) const + { + rtti->remove(ref, inIndex); + } + + QMapMetaView::QMapMetaView(const Mirror::Any& inRef) + : ref(inRef) + { + Assert(inRef.IsRef() && ref.CanAsTemplateView()); + rtti = static_cast(ref.GetTemplateViewRtti()); + } + + const Mirror::TypeInfo* QMapMetaView::GetKeyType() const + { + return rtti->getKeyType(); + } + + const Mirror::TypeInfo* QMapMetaView::GetValueType() const + { + return rtti->getValueType(); + } + + Mirror::Any QMapMetaView::CreateKey() const + { + return rtti->createKey(); + } + + Mirror::Any QMapMetaView::CreateValue() const + { + return rtti->createValue(); + } + + size_t QMapMetaView::GetSize() const + { + return rtti->getSize(ref); + } + + void QMapMetaView::Reserve(size_t inSize) const + { + rtti->reserve(ref, inSize); + } + + void QMapMetaView::Clear() const + { + rtti->clear(ref); + } + + Mirror::Any QMapMetaView::GetOrAdd(const Mirror::Argument& inKey) const + { + return rtti->getOrAdd(ref, inKey); + } + + Mirror::Any QMapMetaView::ConstAt(const Mirror::Argument& inKey) const + { + return rtti->constAt(ref, inKey); + } + + void QMapMetaView::Traverse(const PairTraverser& inTraverser) const + { + rtti->traverse(ref, inTraverser); + } + + void QMapMetaView::ConstTraverse(const PairTraverser& inTraverser) const + { + rtti->constTraverse(ref, inTraverser); + } + + bool QMapMetaView::Contains(const Mirror::Argument& inKey) const + { + return rtti->contains(ref, inKey); + } + + void QMapMetaView::Emplace(const Mirror::Argument& inTempKey, const Mirror::Argument& inTempValue) const + { + rtti->emplace(ref, inTempKey, inTempValue); + } + + void QMapMetaView::Erase(const Mirror::Argument& inKey) const + { + rtti->erase(ref, inKey); + } +} // namespace Editor diff --git a/Editor/Src/QtGlue/Serialization.cpp b/Editor/Src/QtGlue/Serialization.cpp deleted file mode 100644 index cd2cfea1..00000000 --- a/Editor/Src/QtGlue/Serialization.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by johnk on 2025/8/17. -// - -#include diff --git a/Editor/Src/Widget/Editor.cpp b/Editor/Src/Widget/Editor.cpp index 6ffb29d2..e788102b 100644 --- a/Editor/Src/Widget/Editor.cpp +++ b/Editor/Src/Widget/Editor.cpp @@ -6,5 +6,5 @@ #include namespace Editor { - Editor::Editor() = default; + ExplosionEditor::ExplosionEditor() = default; } // namespace Editor diff --git a/Editor/Src/Widget/ProjectHub.cpp b/Editor/Src/Widget/ProjectHub.cpp index ab2ff952..71aad411 100644 --- a/Editor/Src/Widget/ProjectHub.cpp +++ b/Editor/Src/Widget/ProjectHub.cpp @@ -6,27 +6,67 @@ #include #include #include +#include +#include +#include namespace Editor { - ProjectHubBridge::ProjectHubBridge(ProjectHub* parent) + ProjectHubBackend::ProjectHubBackend(ProjectHub* parent) : QObject(parent) - , engineVersion(QString::fromStdString(std::format("v{}.{}.{}", ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR, ENGINE_VERSION_PATCH))) + , recentProjectsFile(Core::Paths::EngineCacheDir() / "Editor" / "ProjectHub" / "RecentProjects.json") + , engineVersion(std::format("v{}.{}.{}", ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR, ENGINE_VERSION_PATCH)) { + const Common::Path projectTemplatesRoot = Core::Paths::EngineResDir() / "Editor" / "ProjectTemplates"; + (void) projectTemplatesRoot.Traverse([this](const Common::Path& inPath) -> bool { + if (inPath.IsFile()) { + return true; + } + projectTemplates.emplace_back(ProjectTemplateInfo { inPath.DirName(), inPath.String() }); + return true; + }); + + if (recentProjectsFile.Exists()) { + Common::JsonDeserializeFromFile(recentProjectsFile.String(), recentProjects); + } + } + + ProjectHubBackend::~ProjectHubBackend() + { + Common::JsonSerializeToFile(recentProjectsFile.String(), recentProjects); } - void ProjectHubBridge::CreateProject() const + void ProjectHubBackend::CreateProject() const { // TODO LogInfo(ProjectHub, "ProjectHubBridge::CreateProject"); } + QString ProjectHubBackend::GetEngineVersion() const + { + return QString::fromStdString(engineVersion); + } + + QJsonValue ProjectHubBackend::GetProjectTemplates() const + { + QJsonValue value; + QtJsonSerialize(value, projectTemplates); + return value; + } + + QJsonValue ProjectHubBackend::GetRecentProjects() const + { + QJsonValue value; + QtJsonSerialize(value, recentProjects); + return value; + } + ProjectHub::ProjectHub(QWidget* inParent) : WebWidget(inParent) { setFixedSize(800, 600); Load("/project-hub"); - bridge = new ProjectHubBridge(this); - GetWebChannel()->registerObject("bridge", bridge); + backend = new ProjectHubBackend(this); + GetWebChannel()->registerObject("backend", backend); } } // namespace Editor diff --git a/Editor/Web/src/pages/project-hub.tsx b/Editor/Web/src/pages/project-hub.tsx index b1997051..bac2aa1d 100644 --- a/Editor/Web/src/pages/project-hub.tsx +++ b/Editor/Web/src/pages/project-hub.tsx @@ -3,93 +3,48 @@ import { QWebChannel } from '@/qwebchannel' import { Tabs, Tab } from '@heroui/tabs'; import { User } from '@heroui/user'; import { Form } from '@heroui/form'; -import { Button } from '@heroui/button'; +import {Button, PressEvent} from '@heroui/button'; import { Input } from '@heroui/input'; import { Chip } from '@heroui/chip'; import { Listbox, ListboxItem } from '@heroui/listbox'; import { Avatar } from '@heroui/avatar'; import { ScrollShadow } from "@heroui/scroll-shadow"; +import { Select, SelectItem } from '@heroui/react'; + +interface RecentProjectInfo { + name: string; + path: string; +} + +interface ProjectTemplateInfo { + name: string; + path: string; +} export default function ProjectHubPage() { const [engineVersion, setEngineVersion] = useState(''); - // TODO fetch from c++ - const [recentlyProjects] = useState([{ - key: '1', - name: 'HelloExplosion1', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '2', - name: 'HelloExplosion2', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '3', - name: 'HelloExplosion3', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '4', - name: 'HelloExplosion4', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '5', - name: 'HelloExplosion5', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '6', - name: 'HelloExplosion6', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '7', - name: 'HelloExplosion7', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '8', - name: 'HelloExplosion8', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '9', - name: 'HelloExplosion9', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '10', - name: 'HelloExplosion10', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '11', - name: 'HelloExplosion11', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '12', - name: 'HelloExplosion12', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }, { - key: '13', - name: 'HelloExplosion13', - icon: '/logo.png', - path: '/path/to/HelloExplosion' - }]); + const [recentProjects, setRecentProjects] = useState(Array); + const [projectTemplates, setProjectTemplates] = useState(Array); useEffect(() => { new QWebChannel(window.qt.webChannelTransport, (channel: QWebChannel) : void => { - window.bridge = channel.objects.bridge; - setEngineVersion(window.bridge.engineVersion); + window.backend = channel.objects.backend; + setEngineVersion(window.backend.engineVersion); + setRecentProjects(window.backend.recentProjects); + setProjectTemplates(window.backend.projectTemplates); }) }, []); - function onCreateProject(): void + function onCreateProject() : void + { + window.backend.CreateProject(); + } + + function onOpenProject(e: PressEvent) : void { - window.bridge.CreateProject(); + // TODO + const index = parseInt(e.target.getAttribute('data-key') as string); + console.error('onOpenProject:', index); } return ( @@ -114,19 +69,19 @@ export default function ProjectHubPage() { className='h-[450px]' size={60}> - {(item) => ( - -
- -
- {item.name} - {item.path} + {recentProjects.map((item, i) => ( + +
+ +
+ {item.name} + {item.path} +
-
- - )} + + ))} @@ -135,6 +90,11 @@ export default function ProjectHubPage() { + diff --git a/Editor/Web/src/qwebchannel.d.ts b/Editor/Web/src/qwebchannel.d.ts index a1555fe5..16e0db20 100644 --- a/Editor/Web/src/qwebchannel.d.ts +++ b/Editor/Web/src/qwebchannel.d.ts @@ -3,6 +3,6 @@ export { QWebChannel } from './qwebchannel.js'; declare global { interface Window { qt: any; - bridge: any; + backend: any; } } diff --git a/Engine/Source/Common/Include/Common/FileSystem.h b/Engine/Source/Common/Include/Common/FileSystem.h index 57d09b98..4c0ed0de 100644 --- a/Engine/Source/Common/Include/Common/FileSystem.h +++ b/Engine/Source/Common/Include/Common/FileSystem.h @@ -22,6 +22,7 @@ namespace Common { std::string String() const; Path Parent() const; std::string FileName() const; + std::string DirName() const; std::string FileNameWithoutExtension() const; bool Empty() const; bool Exists() const; diff --git a/Engine/Source/Common/Include/Common/Math/Math.h b/Engine/Source/Common/Include/Common/Math/Math.h new file mode 100644 index 00000000..fc68f8f7 --- /dev/null +++ b/Engine/Source/Common/Include/Common/Math/Math.h @@ -0,0 +1,18 @@ +// +// Created by Kindem on 2025/8/21. +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/Engine/Source/Common/Include/Common/Serialization.h b/Engine/Source/Common/Include/Common/Serialization.h index dcaa5185..ac48aa5a 100644 --- a/Engine/Source/Common/Include/Common/Serialization.h +++ b/Engine/Source/Common/Include/Common/Serialization.h @@ -993,22 +993,6 @@ namespace Common { } }; - template <> - struct JsonSerializer { - static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const bool& inValue) - { - outJsonValue.SetBool(inValue); - } - - static void JsonDeserialize(const rapidjson::Value& inJsonValue, bool& outValue) - { - if (!inJsonValue.IsBool()) { - return; - } - outValue = inJsonValue.GetBool(); - } - }; - template struct VariantTypeId {}; template struct VariantTypeId { static constexpr size_t value = HashUtils::StrCrc32("std::variant"); }; template struct VariantTypeId { static constexpr size_t value = Serializer::typeId + VariantTypeId::value; }; @@ -1054,6 +1038,22 @@ namespace Common { } }; + template <> + struct JsonSerializer { + static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const bool& inValue) + { + outJsonValue.SetBool(inValue); + } + + static void JsonDeserialize(const rapidjson::Value& inJsonValue, bool& outValue) + { + if (!inJsonValue.IsBool()) { + return; + } + outValue = inJsonValue.GetBool(); + } + }; + template <> struct JsonSerializer { static void JsonSerialize(rapidjson::Value& outJsonValue, rapidjson::Document::AllocatorType& inAllocator, const int8_t& inValue) @@ -1556,8 +1556,8 @@ namespace Common { JsonSerializer::JsonSerialize(typeValue, inAllocator, inValue.index()); rapidjson::Value contentValue; - std::visit([&](auto&& v) -> void { - JsonSerializer>::JsonSerialize(contentValue, inAllocator, v); + std::visit([&](T0&& v) -> void { + JsonSerializer>::JsonSerialize(contentValue, inAllocator, v); }, inValue); outJsonValue.SetObject(); diff --git a/Engine/Source/Common/Include/Common/Utility.h b/Engine/Source/Common/Include/Common/Utility.h index 9da719e7..898ca86c 100644 --- a/Engine/Source/Common/Include/Common/Utility.h +++ b/Engine/Source/Common/Include/Common/Utility.h @@ -54,6 +54,14 @@ namespace Common { template T ToArithmetic(const std::string& inStr); + + template + struct Wrap { + using RawType = T; + }; + + template + struct TupleTypeTraverser {}; } // ------------------------ FlagAndBits Begin ------------------------ @@ -138,6 +146,17 @@ namespace Common { } } + template + struct TupleTypeTraverser> { + template + static void Each(F&& inFunc) + { + (void) std::initializer_list { ([&]() -> void { + inFunc(T()); + }(), 0)... }; + } + }; + template void ForEachBits(BitsForEachFunc&& func) { diff --git a/Engine/Source/Common/Src/FileSystem.cpp b/Engine/Source/Common/Src/FileSystem.cpp index d3464312..f4f9bdf9 100644 --- a/Engine/Source/Common/Src/FileSystem.cpp +++ b/Engine/Source/Common/Src/FileSystem.cpp @@ -91,6 +91,12 @@ namespace Common { return { path.filename().string() }; } + std::string Path::DirName() const + { + Assert(IsDirectory()); + return { path.filename().string() }; + } + std::string Path::FileNameWithoutExtension() const { const auto extension = Extension(); diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 2b523383..5ef823c1 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -22,6 +22,8 @@ #include #include #include +#include +#include #if COMPILER_MSVC #define functionSignature __FUNCSIG__ @@ -65,6 +67,7 @@ namespace Mirror { }; template const TypeInfo* GetTypeInfo(); + template TypeId GetTypeId(); struct TypeInfoCompact { const TypeInfo* raw; @@ -157,7 +160,7 @@ namespace Mirror { GetDynamicClassFunc* getDynamicClass; }; - template + template static constexpr AnyRtti anyRttiImpl = { &AnyRtti::Detor, &AnyRtti::CopyConstruct, @@ -252,7 +255,9 @@ namespace Mirror { template T* TryAs() const; template bool CanAsTemplateView() const; + TemplateViewId GetTemplateViewId() const; TemplateViewRttiPtr GetTemplateViewRtti() const; + bool HasTemplateView() const; bool IsArray() const; Any At(uint32_t inIndex); @@ -990,23 +995,39 @@ namespace Mirror { static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdOptionalView"); using GetElementTypeFunc = const TypeInfo*(); + using ResetFunc = void(const Any&); + using EmplaceFunc = Any(const Any&, const Argument&); + using EmplaceDefaultFunc = Any(const Any&); using HasValueFunc = bool(const Any&); using GetValueFunc = Any(const Any&); + using GetConstValueFunc = Any(const Any&); template static const TypeInfo* GetElementType(); + template static void Reset(const Any& inRef); + template static Any Emplace(const Any& inRef, const Argument& inArg); + template static Any EmplaceDefault(const Any& inRef); template static bool HasValue(const Any& inRef); template static Any GetValue(const Any& inRef); + template static Any GetConstValue(const Any& inRef); GetElementTypeFunc* getElementType; + ResetFunc* reset; + EmplaceFunc* emplace; + EmplaceDefaultFunc* emplaceDefault; HasValueFunc* hasValue; GetValueFunc* getValue; + GetConstValueFunc* getConstValue; }; template static constexpr StdOptionalViewRtti stdOptionalViewRttiImpl = { &StdOptionalViewRtti::GetElementType, + &StdOptionalViewRtti::Reset, + &StdOptionalViewRtti::Emplace, + &StdOptionalViewRtti::EmplaceDefault, &StdOptionalViewRtti::HasValue, - &StdOptionalViewRtti::GetValue + &StdOptionalViewRtti::GetValue, + &StdOptionalViewRtti::GetConstValue }; template @@ -1024,8 +1045,12 @@ namespace Mirror { NonMovable(StdOptionalView) const TypeInfo* ElementType() const; + void Reset() const; + Any Emplace(const Argument& inTempObj) const; + Any EmplaceDefault() const; bool HasValue() const; Any Value() const; + Any ConstValue() const; private: Any ref; @@ -1041,6 +1066,7 @@ namespace Mirror { using GetValueTypeFunc = const TypeInfo*(); using GetKeyFunc = Any(const Any&); using GetValueFunc = Any(const Any&); + using ResetFunc = void(const Any&); template static const TypeInfo* GetKeyType(); template static const TypeInfo* GetValueType(); @@ -1048,6 +1074,7 @@ namespace Mirror { template static Any GetValue(const Any& inRef); template static Any GetConstKey(const Any& inRef); template static Any GetConstValue(const Any& inRef); + template static void Reset(const Any& inRef); GetKeyTypeFunc* getKeyType; GetValueTypeFunc* getValueType; @@ -1055,6 +1082,7 @@ namespace Mirror { GetValueFunc* getValue; GetKeyFunc* getConstKey; GetValueFunc* getConstValue; + ResetFunc* reset; }; template @@ -1064,7 +1092,8 @@ namespace Mirror { &StdPairViewRtti::GetKey, &StdPairViewRtti::GetValue, &StdPairViewRtti::GetConstKey, - &StdPairViewRtti::GetConstValue + &StdPairViewRtti::GetConstValue, + &StdPairViewRtti::Reset, }; template @@ -1087,6 +1116,7 @@ namespace Mirror { Any Value() const; Any ConstKey() const; Any ConstValue() const; + void Reset() const; private: Any ref; @@ -1153,23 +1183,35 @@ namespace Mirror { using GetElementTypeFunc = const TypeInfo*(); using GetSizeFunc = size_t(const Any&); + using ReserveFunc = void(const Any&, size_t); + using ResizeFunc = void(const Any&, size_t); + using ClearFunc = void(const Any&); using GetElementFunc = Any(const Any&, size_t); using GetConstElementFunc = Any(const Any&, size_t); using EmplaceBackFunc = Any(const Any&, const Argument&); + using EmplaceDefaultBackFunc = Any(const Any&); using EraseFunc = void(const Any&, size_t); template static const TypeInfo* GetElementType(); template static size_t GetSize(const Any& inRef); + template static void Reserve(const Any& inRef, size_t inSize); + template static void Resize(const Any& inRef, size_t inSize); + template static void Clear(const Any& inRef); template static Any GetElement(const Any& inRef, size_t inIndex); template static Any GetConstElement(const Any& inRef, size_t inIndex); template static Any EmplaceBack(const Any& inRef, const Argument& inTempObj); + template static Any EmplaceDefaultBack(const Any& inRef); template static void Erase(const Any& inRef, size_t inIndex); GetElementTypeFunc* getElementType; GetSizeFunc* getSize; + ReserveFunc* reserve; + ResizeFunc* resize; + ClearFunc* clear; GetElementFunc* getElement; GetConstElementFunc* getConstElement; EmplaceBackFunc* emplaceBack; + EmplaceDefaultBackFunc* emplaceDefaultBack; EraseFunc* erase; }; @@ -1177,9 +1219,13 @@ namespace Mirror { static constexpr StdVectorViewRtti stdVectorViewRttiImpl = { &StdVectorViewRtti::GetElementType, &StdVectorViewRtti::GetSize, + &StdVectorViewRtti::Reserve, + &StdVectorViewRtti::Resize, + &StdVectorViewRtti::Clear, &StdVectorViewRtti::GetElement, &StdVectorViewRtti::GetConstElement, &StdVectorViewRtti::EmplaceBack, + &StdVectorViewRtti::EmplaceDefaultBack, &StdVectorViewRtti::Erase }; @@ -1199,9 +1245,13 @@ namespace Mirror { const TypeInfo* ElementType() const; size_t Size() const; + void Reserve(size_t inSize) const; + void Resize(size_t inSize) const; + void Clear() const; Any At(size_t inIndex) const; Any ConstAt(size_t inIndex) const; Any EmplaceBack(const Argument& inTempObj) const; + Any EmplaceDefaultBack() const; void Erase(size_t inIndex) const; private: @@ -1216,34 +1266,46 @@ namespace Mirror { using GetElementTypeFunc = const TypeInfo*(); using GetSizeFunc = size_t(const Any&); + using ClearFunc = void(const Any&); using TraverseFunc = void(const Any&, const std::function&); using ConstTraverseFunc = void(const Any&, const std::function&); using EmplaceFrontFunc = Any(const Any&, const Argument&); using EmplaceBackFunc = Any(const Any&, const Argument&); + using EmplaceDefaultFrontFunc = Any(const Any&); + using EmplaceDefaultBackFunc = Any(const Any&); template static const TypeInfo* GetElementType(); template static size_t GetSize(const Any& inRef); + template static void Clear(const Any& inRef); template static void Traverse(const Any& inRef, const std::function& inTraverser); template static void ConstTraverse(const Any& inRef, const std::function& inTraverser); template static Any EmplaceFront(const Any& inRef, const Argument& inTempObj); template static Any EmplaceBack(const Any& inRef, const Argument& inTempObj); + template static Any EmplaceDefaultFront(const Any& inRef); + template static Any EmplaceDefaultBack(const Any& inRef); GetElementTypeFunc* getElementType; GetSizeFunc* getSize; + ClearFunc* clear; TraverseFunc* traverse; ConstTraverseFunc* constTraverse; EmplaceFrontFunc* emplaceFront; EmplaceBackFunc* emplaceBack; + EmplaceDefaultFrontFunc* emplaceDefaultFront; + EmplaceDefaultBackFunc* emplaceDefaultBack; }; template static constexpr StdListViewRtti stdListViewRttiImpl = { &StdListViewRtti::GetElementType, &StdListViewRtti::GetSize, + &StdListViewRtti::Clear, &StdListViewRtti::Traverse, &StdListViewRtti::ConstTraverse, &StdListViewRtti::EmplaceFront, - &StdListViewRtti::EmplaceBack + &StdListViewRtti::EmplaceBack, + &StdListViewRtti::EmplaceDefaultFront, + &StdListViewRtti::EmplaceDefaultBack }; template @@ -1263,10 +1325,13 @@ namespace Mirror { const TypeInfo* ElementType() const; size_t Size() const; + void Clear() const; void Traverse(const ElementTraverser& inTraverser) const; void ConstTraverse(const ElementTraverser& inTraverser) const; Any EmplaceFront(const Argument& inTempObj) const; Any EmplaceBack(const Argument& inTempObj) const; + Any EmplaceDefaultFront() const; + Any EmplaceDefaultBack() const; private: Any ref; @@ -1279,7 +1344,10 @@ namespace Mirror { static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdUnorderedSetView"); using GetElementTypeFunc = const TypeInfo*(); + using CreateElementFunc = Any(); using GetSizeFunc = size_t(const Any&); + using ReserveFunc = void(const Any&, size_t); + using ClearFunc = void(const Any&); using TraverseFunc = void(const Any&, const std::function&); using ConstTraverseFunc = void(const Any&, const std::function&); using ContainsFunc = bool(const Any&, const Argument&); @@ -1287,7 +1355,10 @@ namespace Mirror { using EraseFunc = void(const Any&, const Argument&); template static const TypeInfo* GetElementType(); + template static Any CreateElement(); template static size_t GetSize(const Any& inRef); + template static void Reserve(const Any& inRef, size_t inSize); + template static void Clear(const Any& inRef); template static void Traverse(const Any& inRef, const std::function& inTraverser); template static void ConstTraverse(const Any& inRef, const std::function& inTraverser); template static bool Contains(const Any& inRef, const Argument& inElement); @@ -1295,7 +1366,10 @@ namespace Mirror { template static void Erase(const Any& inRef, const Argument& inElement); GetElementTypeFunc* getElementType; + CreateElementFunc* createElement; GetSizeFunc* getSize; + ReserveFunc* reserve; + ClearFunc* clear; TraverseFunc* traverse; ConstTraverseFunc* constTraverse; ContainsFunc* contains; @@ -1306,7 +1380,10 @@ namespace Mirror { template static constexpr StdUnorderedSetViewRtti stdUnorderedSetViewRttiImpl = { &StdUnorderedSetViewRtti::GetElementType, + &StdUnorderedSetViewRtti::CreateElement, &StdUnorderedSetViewRtti::GetSize, + &StdUnorderedSetViewRtti::Reserve, + &StdUnorderedSetViewRtti::Clear, &StdUnorderedSetViewRtti::Traverse, &StdUnorderedSetViewRtti::ConstTraverse, &StdUnorderedSetViewRtti::Contains, @@ -1330,7 +1407,10 @@ namespace Mirror { NonMovable(StdUnorderedSetView) const TypeInfo* ElementType() const; + Any CreateElement() const; size_t Size() const; + void Reserve(size_t inSize) const; + void Clear() const; void Traverse(const ElementTraverser& inTraverser) const; void ConstTraverse(const ElementTraverser& inTraverser) const; bool Contains(const Argument& inElement) const; @@ -1348,22 +1428,31 @@ namespace Mirror { static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdSetView"); using GetElementTypeFunc = const TypeInfo*(); + using CreateElementFunc = Any(); using GetSizeFunc = size_t(const Any&); + using ClearFunc = void(const Any&); using TraverseFunc = void(const Any&, const std::function&); + using ConstTraverseFunc = void(const Any&, const std::function&); using ContainsFunc = bool(const Any&, const Argument&); using EmplaceFunc = void(const Any&, const Argument&); using EraseFunc = void(const Any&, const Argument&); template static const TypeInfo* GetElementType(); + template static Any CreateElement(); template static size_t GetSize(const Any& inRef); + template static void Clear(const Any& inRef); template static void Traverse(const Any& inRef, const std::function& inTraverser); + template static void ConstTraverse(const Any& inRef, const std::function& inTraverser); template static bool Contains(const Any& inRef, const Argument& inElement); template static void Emplace(const Any& inRef, const Argument& inTempObj); template static void Erase(const Any& inRef, const Argument& inElement); GetElementTypeFunc* getElementType; + CreateElementFunc* createElement; GetSizeFunc* getSize; + ClearFunc* clear; TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; ContainsFunc* contains; EmplaceFunc* emplace; EraseFunc* erase; @@ -1372,8 +1461,11 @@ namespace Mirror { template static constexpr StdSetViewRtti stdSetViewRttiImpl = { &StdSetViewRtti::GetElementType, + &StdSetViewRtti::CreateElement, &StdSetViewRtti::GetSize, + &StdSetViewRtti::Clear, &StdSetViewRtti::Traverse, + &StdSetViewRtti::ConstTraverse, &StdSetViewRtti::Contains, &StdSetViewRtti::Emplace, &StdSetViewRtti::Erase @@ -1395,8 +1487,11 @@ namespace Mirror { NonMovable(StdSetView) const TypeInfo* ElementType() const; + Any CreateElement() const; size_t Size() const; + void Clear() const; void Traverse(const ElementTraverser& inTraverser) const; + void ConstTraverse(const ElementTraverser& inTraverser) const; bool Contains(const Argument& inElement) const; void Emplace(const Argument& inTempObj) const; void Erase(const Argument& inElement) const; @@ -1413,8 +1508,13 @@ namespace Mirror { using GetKeyTypeFunc = const TypeInfo*(); using GetValueTypeFunc = const TypeInfo*(); + using CreateKeyFunc = Any(); + using CreateValueFunc = Any(); using GetSizeFunc = size_t(const Any&); + using ReserveFunc = void(const Any&, size_t); + using ClearFunc = void(const Any&); using AtFunc = Any(const Any&, const Argument&); + using ConstAtFunc = Any(const Any&, const Argument&); using GetOrAddFunc = Any(const Any&, const Argument&); using TraverseFunc = void(const Any&, const std::function&); using ConstTraverseFunc = void(const Any&, const std::function&); @@ -1424,8 +1524,13 @@ namespace Mirror { template static const TypeInfo* GetKeyType(); template static const TypeInfo* GetValueType(); + template static Any CreateKey(); + template static Any CreateValue(); template static size_t GetSize(const Any& inRef); + template static void Reserve(const Any& inRef, size_t inSize); + template static void Clear(const Any& inRef); template static Any At(const Any& inRef, const Argument& inKey); + template static Any ConstAt(const Any& inRef, const Argument& inKey); template static Any GetOrAdd(const Any& inRef, const Argument& inKey); template static void Traverse(const Any& inRef, const std::function& inTraverser); template static void ConstTraverse(const Any& inRef, const std::function& inTraverser); @@ -1435,8 +1540,13 @@ namespace Mirror { GetKeyTypeFunc* getKeyType; GetValueTypeFunc* getValueType; + CreateKeyFunc* createKey; + CreateValueFunc* createValue; GetSizeFunc* getSize; + ReserveFunc* reserve; + ClearFunc* clear; AtFunc* at; + ConstAtFunc* constAt; GetOrAddFunc* getOrAdd; TraverseFunc* traverse; ConstTraverseFunc* constTraverse; @@ -1449,8 +1559,13 @@ namespace Mirror { static constexpr StdUnorderedMapViewRtti stdUnorderedMapViewRttiImpl = { &StdUnorderedMapViewRtti::GetKeyType, &StdUnorderedMapViewRtti::GetValueType, + &StdUnorderedMapViewRtti::CreateKey, + &StdUnorderedMapViewRtti::CreateValue, &StdUnorderedMapViewRtti::GetSize, + &StdUnorderedMapViewRtti::Reserve, + &StdUnorderedMapViewRtti::Clear, &StdUnorderedMapViewRtti::At, + &StdUnorderedMapViewRtti::ConstAt, &StdUnorderedMapViewRtti::GetOrAdd, &StdUnorderedMapViewRtti::Traverse, &StdUnorderedMapViewRtti::ConstTraverse, @@ -1476,8 +1591,13 @@ namespace Mirror { const TypeInfo* KeyType() const; const TypeInfo* ValueType() const; + Any CreateKey() const; + Any CreateValue() const; size_t Size() const; + void Reserve(size_t inSize) const; + void Clear() const; Any At(const Argument& inKey) const; + Any ConstAt(const Argument& inKey) const; Any GetOrAdd(const Argument& inKey) const; void Traverse(const PairTraverser& inTraverser) const; void ConstTraverse(const PairTraverser& inTraverser) const; @@ -1497,8 +1617,12 @@ namespace Mirror { using GetKeyTypeFunc = const TypeInfo*(); using GetValueTypeFunc = const TypeInfo*(); + using CreateKeyFunc = Any(); + using CreateValueFunc = Any(); using GetSizeFunc = size_t(const Any&); + using ClearFunc = void(const Any&); using AtFunc = Any(const Any&, const Argument&); + using ConstAtFunc = Any(const Any&, const Argument&); using GetOrAddFunc = Any(const Any&, const Argument&); using TraverseFunc = void(const Any&, const std::function&); using ConstTraverseFunc = void(const Any&, const std::function&); @@ -1508,8 +1632,12 @@ namespace Mirror { template static const TypeInfo* GetKeyType(); template static const TypeInfo* GetValueType(); + template static Any CreateKey(); + template static Any CreateValue(); template static size_t GetSize(const Any& inRef); + template static void Clear(const Any& inRef); template static Any At(const Any& inRef, const Argument& inKey); + template static Any ConstAt(const Any& inRef, const Argument& inKey); template static Any GetOrAdd(const Any& inRef, const Argument& inKey); template static void Traverse(const Any& inRef, const std::function& inTraverser); template static void ConstTraverse(const Any& inRef, const std::function& inTraverser); @@ -1519,8 +1647,12 @@ namespace Mirror { GetKeyTypeFunc* getKeyType; GetValueTypeFunc* getValueType; + CreateKeyFunc* createKey; + CreateValueFunc* createValue; GetSizeFunc* getSize; + ClearFunc* clear; AtFunc* at; + ConstAtFunc* constAt; GetOrAddFunc* getOrAdd; TraverseFunc* traverse; ConstTraverseFunc* constTraverse; @@ -1533,8 +1665,12 @@ namespace Mirror { static constexpr StdMapViewRtti stdMapViewRttiImpl = { &StdMapViewRtti::GetKeyType, &StdMapViewRtti::GetValueType, + &StdMapViewRtti::CreateKey, + &StdMapViewRtti::CreateValue, &StdMapViewRtti::GetSize, + &StdMapViewRtti::Clear, &StdMapViewRtti::At, + &StdMapViewRtti::ConstAt, &StdMapViewRtti::GetOrAdd, &StdMapViewRtti::Traverse, &StdMapViewRtti::ConstTraverse, @@ -1560,8 +1696,12 @@ namespace Mirror { const TypeInfo* KeyType() const; const TypeInfo* ValueType() const; + Any CreateKey() const; + Any CreateValue() const; size_t Size() const; + void Clear() const; Any At(const Argument& inKey) const; + Any ConstAt(const Argument& inKey) const; Any GetOrAdd(const Argument& inKey) const; void Traverse(const PairTraverser& inTraverser) const; void ConstTraverse(const PairTraverser& inTraverser) const; @@ -1581,26 +1721,38 @@ namespace Mirror { using GetSizeFunc = size_t(); using GetElementTypeFunc = const TypeInfo*(size_t); + using CreateElementFunc = Any(size_t); using GetElementFunc = Any(const Any&, size_t); - using TraverseFunc = void(const Any&, const std::function&); + using GetConstElementFunc = Any(const Any&, size_t); + using TraverseFunc = void(const Any&, const std::function&); + using ConstTraverseFunc = void(const Any&, const std::function&); template static size_t GetSize(); template static const TypeInfo* GetElementType(size_t inIndex); + template static Any CreateElement(size_t inIndex); template static Any GetElement(const Any& inRef, size_t inIndex); - template static void Traverse(const Any& inRef, const std::function& inVisitor); + template static Any GetConstElement(const Any& inRef, size_t inIndex); + template static void Traverse(const Any& inRef, const std::function& inVisitor); + template static void ConstTraverse(const Any& inRef, const std::function& inVisitor); GetSizeFunc* getSize; GetElementTypeFunc* getElementType; + CreateElementFunc* createElement; GetElementFunc* getElement; + GetConstElementFunc* getConstElement; TraverseFunc* traverse; + ConstTraverseFunc* constTraverse; }; template static constexpr StdTupleRtti stdTupleRttiImpl = { &StdTupleRtti::GetSize, &StdTupleRtti::GetElementType, + &StdTupleRtti::CreateElement, &StdTupleRtti::GetElement, - &StdTupleRtti::Traverse + &StdTupleRtti::GetConstElement, + &StdTupleRtti::Traverse, + &StdTupleRtti::ConstTraverse }; template @@ -1611,7 +1763,7 @@ namespace Mirror { class MIRROR_API StdTupleView { public: - using Visitor = std::function; + using Traverser = std::function; static constexpr TemplateViewId id = StdTupleRtti::id; explicit StdTupleView(const Any& inRef); @@ -1620,14 +1772,94 @@ namespace Mirror { size_t Size() const; const TypeInfo* ElementType(size_t inIndex) const; + Any CreateElement(size_t inIndex) const; Any Get(size_t inIndex) const; - void Traverse(const Visitor& inVisitor) const; + void Traverse(const Traverser& inVisitor) const; + void ConstTraverse(const Traverser& inVisitor) const; private: Any ref; const StdTupleRtti* rtti; }; // --------------- end std::tuple ------------------- + + // --------------- begin std::variant --------------- + struct StdVariantRtti { + static constexpr TemplateViewId id = Common::HashUtils::StrCrc32("Mirror::StdVariantView"); + + using TypeNumFunc = size_t(); + using TypeByIndexFunc = const TypeInfo*(size_t); + using CreateElementFunc = Any(size_t); + using IndexFunc = size_t(const Any&); + using GetElementFunc = Any(const Any&, size_t); + using GetConstElementFunc = Any(const Any&, size_t); + using VisitFunc = void(const Any&, const std::function&); + using ConstVisitFunc = void(const Any&, const std::function&); + using EmplaceFunc = Any(const Any&, size_t, const Argument&); + + template static size_t TypeNum(); + template static const TypeInfo* TypeByIndex(size_t inIndex); + template static Any CreateElement(size_t inIndex); + template static size_t Index(const Any& inRef); + template static Any GetElement(const Any& inRef, size_t inIndex); + template static Any GetConstElement(const Any& inRef, size_t inIndex); + template static void Visit(const Any& inRef, const std::function& inVisitor); + template static void ConstVisit(const Any& inRef, const std::function& inVisitor); + template static Any Emplace(const Any& inRef, size_t inIndex, const Argument& inTempObj); + + TypeNumFunc* typeNum; + TypeByIndexFunc* typeByIndex; + CreateElementFunc* createElement; + IndexFunc* index; + GetElementFunc* getElement; + GetConstElementFunc* getConstElement; + VisitFunc* visit; + ConstVisitFunc* constVisit; + EmplaceFunc* emplace; + }; + + template + static constexpr StdVariantRtti stdVariantRttiImpl = { + &StdVariantRtti::TypeNum, + &StdVariantRtti::TypeByIndex, + &StdVariantRtti::CreateElement, + &StdVariantRtti::Index, + &StdVariantRtti::GetElement, + &StdVariantRtti::GetConstElement, + &StdVariantRtti::Visit, + &StdVariantRtti::ConstVisit, + &StdVariantRtti::Emplace + }; + + template + struct TemplateViewRttiGetter> { + static constexpr TemplateViewId Id(); + static const void* Get(); + }; + + class MIRROR_API StdVariantView { + public: + using Visitor = std::function; + static constexpr TemplateViewId id = StdVariantRtti::id; + + explicit StdVariantView(const Any& inRef); + NonCopyable(StdVariantView) + NonMovable(StdVariantView) + + size_t TypeNum() const; + const TypeInfo* TypeByIndex(size_t inIndex) const; + Any CreateElement(size_t inIndex) const; + size_t Index() const; + Any GetElement(size_t inIndex) const; + Any GetConstElement(size_t inIndex) const; + void Visit(const Visitor& inVisitor) const; + Any Emplace(size_t inIndex, const Argument& inTempObj) const; + + private: + Any ref; + const StdVariantRtti* rtti; + }; + // --------------- end std::variant ----------------- } namespace Mirror::Internal { @@ -1640,6 +1872,16 @@ namespace Mirror::Internal { "static version reflection method do no support use Any/Any*/const Any*/Argument as argument, please check you arguments"); } + template + static std::array, sizeof...(T)> BuildTupleDynElementCreatorArray(std::index_sequence) + { + return { + []() -> Any { + return T(); + }... + }; + } + template static std::array, sizeof...(T)> BuildTupleDynGetterArray(std::index_sequence) { @@ -1651,13 +1893,62 @@ namespace Mirror::Internal { } template - static void TraverseTupleDyn(const Argument& inObj, const std::function& inVisitor, std::index_sequence) + static std::array, sizeof...(T)> BuildTupleDynConstGetterArray(std::index_sequence) + { + return { + [](const Argument& inObj) -> Any { + return std::get(inObj.As&>()); + }... + }; + } + + template + static void TraverseTupleDyn(const Argument& inObj, const std::function& inVisitor, std::index_sequence) { auto& tuple = inObj.As&>(); (void) std::initializer_list { ([&]() -> void { - inVisitor(std::ref(std::get(tuple))); + inVisitor(std::ref(std::get(tuple)), I); + }(), 0)... }; + } + + template + static void ConstTraverseTupleDyn(const Argument& inObj, const std::function& inVisitor, std::index_sequence) + { + const auto& tuple = inObj.As&>(); + (void) std::initializer_list { ([&]() -> void { + inVisitor(std::ref(std::get(tuple)), I); }(), 0)... }; } + + template + static std::array, sizeof...(T)> BuildVariantDynGetterArray(std::index_sequence) + { + return { + [](const Argument& inObj) -> Any { + return std::get(inObj.As&>()); + }... + }; + } + + template + static std::array, sizeof...(T)> BuildVariantDynConstGetterArray(std::index_sequence) + { + return { + [](const Argument& inObj) -> Any { + return std::get(inObj.As&>()); + }... + }; + } + + template + static std::array, sizeof...(T)> BuildVariantDynEmplaceFuncArray(std::index_sequence) + { + return { + [](const Argument& inObj, const Argument& inTempObj) -> Any { + return inObj.As&>().template emplace(std::move(inTempObj.As())); + }... + }; + } } namespace Common { // NOLINT @@ -2725,6 +3016,12 @@ namespace Mirror { return &typeInfo; } + template + TypeId GetTypeId() + { + return GetTypeInfo()->id; + } + template void AnyRtti::Detor(void* inThis) noexcept { @@ -3442,6 +3739,24 @@ namespace Mirror { return GetTypeInfo(); } + template + void StdOptionalViewRtti::Reset(const Any& inRef) + { + inRef.As&>().reset(); + } + + template + Any StdOptionalViewRtti::Emplace(const Any& inRef, const Argument& inArg) + { + return std::ref(inRef.As&>().emplace(std::move(inArg.As()))); + } + + template + Any StdOptionalViewRtti::EmplaceDefault(const Any& inRef) + { + return std::ref(inRef.As&>().emplace()); + } + template bool StdOptionalViewRtti::HasValue(const Any& inRef) { @@ -3450,6 +3765,12 @@ namespace Mirror { template Any StdOptionalViewRtti::GetValue(const Any& inRef) + { + return std::ref(inRef.As&>().value()); + } + + template + Any StdOptionalViewRtti::GetConstValue(const Any& inRef) { return std::ref(inRef.As&>().value()); } @@ -3481,25 +3802,31 @@ namespace Mirror { template Any StdPairViewRtti::GetKey(const Any& inRef) { - return { std::ref(inRef.As&>().first) }; + return std::ref(inRef.As&>().first); } template Any StdPairViewRtti::GetValue(const Any& inRef) { - return { std::ref(inRef.As&>().second) }; + return std::ref(inRef.As&>().second); } template Any StdPairViewRtti::GetConstKey(const Any& inRef) { - return { std::ref(inRef.As&>().first) }; + return std::ref(inRef.As&>().first); } template Any StdPairViewRtti::GetConstValue(const Any& inRef) { - return { std::ref(inRef.As&>().second) }; + return std::ref(inRef.As&>().second); + } + + template + void StdPairViewRtti::Reset(const Any& inRef) + { + inRef.As&>() = {}; } template @@ -3562,13 +3889,31 @@ namespace Mirror { return inRef.As&>().size(); } + template + void StdVectorViewRtti::Reserve(const Any& inRef, size_t inSize) + { + inRef.As&>().reserve(inSize); + } + + template + void StdVectorViewRtti::Resize(const Any& inRef, size_t inSize) + { + inRef.As&>().resize(inSize); + } + + template + void StdVectorViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template Any StdVectorViewRtti::GetElement(const Any& inRef, size_t inIndex) { if constexpr (std::is_same_v) { - return { inRef.As&>()[inIndex] }; + return inRef.As&>()[inIndex]; } else { - return { std::ref(inRef.As&>()[inIndex]) }; + return std::ref(inRef.As&>()[inIndex]); } } @@ -3576,9 +3921,9 @@ namespace Mirror { Any StdVectorViewRtti::GetConstElement(const Any& inRef, size_t inIndex) { if constexpr (std::is_same_v) { - return { inRef.As&>()[inIndex] }; + return inRef.As&>()[inIndex]; } else { - return { std::ref(inRef.As&>()[inIndex]) }; + return std::ref(inRef.As&>()[inIndex]); } } @@ -3586,9 +3931,19 @@ namespace Mirror { Any StdVectorViewRtti::EmplaceBack(const Any& inRef, const Argument& inTempObj) { if constexpr (std::is_same_v) { - return { inRef.As&>().emplace_back(std::move(inTempObj.As())) }; + return inRef.As&>().emplace_back(std::move(inTempObj.As())); + } else { + return std::ref(inRef.As&>().emplace_back(std::move(inTempObj.As()))); + } + } + + template + Any StdVectorViewRtti::EmplaceDefaultBack(const Any& inRef) + { + if constexpr (std::is_same_v) { + return inRef.As&>().emplace_back(); } else { - return { std::ref(inRef.As&>().emplace_back(std::move(inTempObj.As()))) }; + return std::ref(inRef.As&>().emplace_back()); } } @@ -3623,6 +3978,12 @@ namespace Mirror { return inRef.As&>().size(); } + template + void StdListViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template void StdListViewRtti::Traverse(const Any& inRef, const std::function& inTraverser) { @@ -3655,6 +4016,20 @@ namespace Mirror { return { std::ref(elemRef) }; } + template + Any StdListViewRtti::EmplaceDefaultFront(const Any& inRef) + { + T& elemRef = inRef.As&>().emplace_front(); + return { std::ref(elemRef) }; + } + + template + Any StdListViewRtti::EmplaceDefaultBack(const Any& inRef) + { + T& elemRef = inRef.As&>().emplace_back(); + return { std::ref(elemRef) }; + } + template constexpr TemplateViewId TemplateViewRttiGetter>::Id() { @@ -3673,12 +4048,30 @@ namespace Mirror { return GetTypeInfo(); } + template + Any StdUnorderedSetViewRtti::CreateElement() + { + return { T() }; + } + template size_t StdUnorderedSetViewRtti::GetSize(const Any& inRef) { return inRef.As&>().size(); } + template + void StdUnorderedSetViewRtti::Reserve(const Any& inRef, size_t inSize) + { + inRef.As&>().reserve(inSize); + } + + template + void StdUnorderedSetViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template void StdUnorderedSetViewRtti::Traverse(const Any& inRef, const std::function& inTraverser) { @@ -3733,16 +4126,37 @@ namespace Mirror { return GetTypeInfo(); } + template + Any StdSetViewRtti::CreateElement() + { + return { T() }; + } + template size_t StdSetViewRtti::GetSize(const Any& inRef) { return inRef.As&>().size(); } + template + void StdSetViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template void StdSetViewRtti::Traverse(const Any& inRef, const std::function& inTraverser) { - const auto& set = inRef.As&>(); // NOLINT + auto& set = inRef.As&>(); + for (auto& element : set) { + inTraverser(std::ref(element)); + } + } + + template + void StdSetViewRtti::ConstTraverse(const Any& inRef, const std::function& inTraverser) + { + const auto& set = inRef.As&>(); for (const auto& element : set) { inTraverser(std::ref(element)); } @@ -3790,18 +4204,48 @@ namespace Mirror { return GetTypeInfo(); } + template + Any StdUnorderedMapViewRtti::CreateKey() + { + return { K() }; + } + + template + Any StdUnorderedMapViewRtti::CreateValue() + { + return { V() }; + } + template size_t StdUnorderedMapViewRtti::GetSize(const Any& inRef) { return inRef.As&>().size(); } + template + void StdUnorderedMapViewRtti::Reserve(const Any& inRef, size_t inSize) + { + inRef.As&>().reserve(inSize); + } + + template + void StdUnorderedMapViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template Any StdUnorderedMapViewRtti::At(const Any& inRef, const Argument& inKey) { return { std::ref(inRef.As&>().at(inKey.As())) }; } + template + Any StdUnorderedMapViewRtti::ConstAt(const Any& inRef, const Argument& inKey) + { + return { std::ref(inRef.As&>().at(inKey.As())) }; + } + template Any StdUnorderedMapViewRtti::GetOrAdd(const Any& inRef, const Argument& inKey) { @@ -3868,18 +4312,42 @@ namespace Mirror { return GetTypeInfo(); } + template + Any StdMapViewRtti::CreateKey() + { + return { K() }; + } + + template + Any StdMapViewRtti::CreateValue() + { + return { V() }; + } + template size_t StdMapViewRtti::GetSize(const Any& inRef) { return inRef.As&>().size(); } + template + void StdMapViewRtti::Clear(const Any& inRef) + { + inRef.As&>().clear(); + } + template Any StdMapViewRtti::At(const Any& inRef, const Argument& inKey) { return { std::ref(inRef.As&>().at(inKey.As())) }; } + template + Any StdMapViewRtti::ConstAt(const Any& inRef, const Argument& inKey) + { + return { std::ref(inRef.As&>().at(inKey.As())) }; + } + template Any StdMapViewRtti::GetOrAdd(const Any& inRef, const Argument& inKey) { @@ -3948,6 +4416,14 @@ namespace Mirror { return types[inIndex]; } + template + Any StdTupleRtti::CreateElement(size_t inIndex) + { + static std::array, sizeof...(T)> creators = Internal::BuildTupleDynElementCreatorArray(std::make_index_sequence {}); + Assert(inIndex < creators.size()); + return creators[inIndex](); + } + template Any StdTupleRtti::GetElement(const Any& inRef, size_t inIndex) { @@ -3957,11 +4433,25 @@ namespace Mirror { } template - void StdTupleRtti::Traverse(const Any& inRef, const std::function& inVisitor) + Any StdTupleRtti::GetConstElement(const Any& inRef, size_t inIndex) + { + static std::array, sizeof...(T)> getters = Internal::BuildTupleDynConstGetterArray(std::make_index_sequence {}); + Assert(inIndex < getters.size()); + return getters[inIndex](inRef); + } + + template + void StdTupleRtti::Traverse(const Any& inRef, const std::function& inVisitor) { Internal::TraverseTupleDyn(inRef, inVisitor, std::make_index_sequence {}); } + template + void StdTupleRtti::ConstTraverse(const Any& inRef, const std::function& inVisitor) + { + Internal::ConstTraverseTupleDyn(inRef, inVisitor, std::make_index_sequence {}); + } + template constexpr TemplateViewId TemplateViewRttiGetter>::Id() { @@ -3973,4 +4463,79 @@ namespace Mirror { { return &stdTupleRttiImpl; } + + template + size_t StdVariantRtti::TypeNum() + { + return sizeof...(T); + } + + template + const TypeInfo* StdVariantRtti::TypeByIndex(size_t inIndex) + { + static std::array types = { GetTypeInfo()... }; + return types[inIndex]; + } + + template + Any StdVariantRtti::CreateElement(size_t inIndex) + { + static std::array, sizeof...(T)> creators = { []() -> Any { return T(); }... }; + return creators[inIndex](); + } + + template + size_t StdVariantRtti::Index(const Any& inRef) + { + return inRef.As&>().index(); + } + + template + Any StdVariantRtti::GetElement(const Any& inRef, size_t inIndex) + { + static auto getters = Internal::BuildVariantDynGetterArray(std::make_index_sequence {}); + return getters[inIndex](inRef); + } + + template + Any StdVariantRtti::GetConstElement(const Any& inRef, size_t inIndex) + { + static auto constGetters = Internal::BuildVariantDynConstGetterArray(std::make_index_sequence {}); + return constGetters[inIndex](inRef); + } + + template + void StdVariantRtti::Visit(const Any& inRef, const std::function& inVisitor) + { + std::visit([&](T0&& inValue) -> void { + inVisitor(std::ref(inValue)); + }, inRef.As&>()); + } + + template + void StdVariantRtti::ConstVisit(const Any& inRef, const std::function& inVisitor) + { + std::visit([&](T0&& inValue) -> void { + inVisitor(std::ref(inValue)); + }, inRef.As&>()); + } + + template + Any StdVariantRtti::Emplace(const Any& inRef, size_t inIndex, const Argument& inTempObj) + { + static auto emplaceFuncs = Internal::BuildVariantDynEmplaceFuncArray(std::make_index_sequence {}); + return emplaceFuncs[inIndex](inRef, inTempObj); + } + + template + constexpr TemplateViewId TemplateViewRttiGetter>::Id() + { + return StdVariantRtti::id; + } + + template + const void* TemplateViewRttiGetter>::Get() + { + return &stdVariantRttiImpl; + } } // namespace Mirror diff --git a/Engine/Source/Mirror/Src/Mirror.cpp b/Engine/Source/Mirror/Src/Mirror.cpp index 81bdd89a..ea4f305c 100644 --- a/Engine/Source/Mirror/Src/Mirror.cpp +++ b/Engine/Source/Mirror/Src/Mirror.cpp @@ -89,7 +89,7 @@ namespace Mirror { { if (IsMemoryHolder() && rtti != nullptr) { for (auto i = 0; i < ElementNum(); i++) { - rtti->detor(Data(i)); + // rtti->detor(Data(i)); } } } @@ -348,12 +348,24 @@ namespace Mirror { return std::max(1u, arrayLength); } + TemplateViewId Any::GetTemplateViewId() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().first; + } + TemplateViewRttiPtr Any::GetTemplateViewRtti() const { Assert(!Empty()); return rtti->getTemplateViewRtti().second; } + bool Any::HasTemplateView() const + { + Assert(!Empty()); + return rtti->getTemplateViewRtti().second != nullptr; + } + bool Any::IsArray() const { return arrayLength > 0; @@ -2027,6 +2039,21 @@ namespace Mirror { return rtti->getElementType(); } + void StdOptionalView::Reset() const + { + rtti->reset(ref); + } + + Any StdOptionalView::Emplace(const Argument& inTempObj) const + { + return rtti->emplace(ref, inTempObj); + } + + Any StdOptionalView::EmplaceDefault() const + { + return rtti->emplaceDefault(ref); + } + bool StdOptionalView::HasValue() const { return rtti->hasValue(ref); @@ -2037,6 +2064,11 @@ namespace Mirror { return rtti->getValue(ref); } + Any StdOptionalView::ConstValue() const + { + return rtti->getConstValue(ref); + } + StdPairView::StdPairView(const Any& inRef) : ref(inRef) { @@ -2074,6 +2106,11 @@ namespace Mirror { return rtti->getConstValue(ref); } + void StdPairView::Reset() const + { + rtti->reset(ref); + } + StdArrayView::StdArrayView(const Any& inRef) : ref(inRef) { @@ -2118,6 +2155,21 @@ namespace Mirror { return rtti->getSize(ref); } + void StdVectorView::Reserve(size_t inSize) const + { + rtti->reserve(ref, inSize); + } + + void StdVectorView::Resize(size_t inSize) const + { + rtti->resize(ref, inSize); + } + + void StdVectorView::Clear() const + { + rtti->clear(ref); + } + Any StdVectorView::At(size_t inIndex) const { return rtti->getElement(ref, inIndex); @@ -2133,6 +2185,11 @@ namespace Mirror { return rtti->emplaceBack(ref, inTempObj); } + Any StdVectorView::EmplaceDefaultBack() const + { + return rtti->emplaceDefaultBack(ref); + } + void StdVectorView::Erase(size_t inIndex) const { rtti->erase(ref, inIndex); @@ -2155,6 +2212,11 @@ namespace Mirror { return rtti->getSize(ref); } + void StdListView::Clear() const + { + rtti->clear(ref); + } + void StdListView::Traverse(const ElementTraverser& inTraverser) const { rtti->traverse(ref, inTraverser); @@ -2175,6 +2237,16 @@ namespace Mirror { return rtti->emplaceBack(ref, inTempObj); } + Any StdListView::EmplaceDefaultFront() const + { + return rtti->emplaceDefaultFront(ref); + } + + Any StdListView::EmplaceDefaultBack() const + { + return rtti->emplaceDefaultBack(ref); + } + StdUnorderedSetView::StdUnorderedSetView(const Any& inRef) : ref(inRef) { @@ -2187,11 +2259,26 @@ namespace Mirror { return rtti->getElementType(); } + Any StdUnorderedSetView::CreateElement() const + { + return rtti->createElement(); + } + size_t StdUnorderedSetView::Size() const { return rtti->getSize(ref); } + void StdUnorderedSetView::Reserve(size_t inSize) const + { + rtti->reserve(ref, inSize); + } + + void StdUnorderedSetView::Clear() const + { + rtti->clear(ref); + } + void StdUnorderedSetView::Traverse(const ElementTraverser& inTraverser) const { rtti->traverse(ref, inTraverser); @@ -2229,16 +2316,31 @@ namespace Mirror { return rtti->getElementType(); } + Any StdSetView::CreateElement() const + { + return rtti->createElement(); + } + size_t StdSetView::Size() const { return rtti->getSize(ref); } + void StdSetView::Clear() const + { + rtti->clear(ref); + } + void StdSetView::Traverse(const ElementTraverser& inTraverser) const { rtti->traverse(ref, inTraverser); } + void StdSetView::ConstTraverse(const ElementTraverser& inTraverser) const + { + rtti->constTraverse(ref, inTraverser); + } + bool StdSetView::Contains(const Argument& inElement) const { return rtti->contains(ref, inElement); @@ -2271,16 +2373,41 @@ namespace Mirror { return rtti->getValueType(); } + Any StdUnorderedMapView::CreateKey() const + { + return rtti->createKey(); + } + + Any StdUnorderedMapView::CreateValue() const + { + return rtti->createValue(); + } + size_t StdUnorderedMapView::Size() const { return rtti->getSize(ref); } + void StdUnorderedMapView::Reserve(size_t inSize) const + { + rtti->reserve(ref, inSize); + } + + void StdUnorderedMapView::Clear() const + { + rtti->clear(ref); + } + Any StdUnorderedMapView::At(const Argument& inKey) const { return rtti->at(ref, inKey); } + Any StdUnorderedMapView::ConstAt(const Argument& inKey) const + { + return rtti->constAt(ref, inKey); + } + Any StdUnorderedMapView::GetOrAdd(const Argument& inKey) const { return rtti->getOrAdd(ref, inKey); @@ -2328,16 +2455,36 @@ namespace Mirror { return rtti->getValueType(); } + Any StdMapView::CreateKey() const + { + return rtti->createKey(); + } + + Any StdMapView::CreateValue() const + { + return rtti->createValue(); + } + size_t StdMapView::Size() const { return rtti->getSize(ref); } + void StdMapView::Clear() const + { + rtti->clear(ref); + } + Any StdMapView::At(const Argument& inKey) const { return rtti->at(ref, inKey); } + Any StdMapView::ConstAt(const Argument& inKey) const + { + return rtti->constAt(ref, inKey); + } + Any StdMapView::GetOrAdd(const Argument& inKey) const { return rtti->getOrAdd(ref, inKey); @@ -2385,13 +2532,68 @@ namespace Mirror { return rtti->getElementType(inIndex); } + Any StdTupleView::CreateElement(size_t inIndex) const + { + return rtti->createElement(inIndex); + } + Any StdTupleView::Get(size_t inIndex) const { return rtti->getElement(ref, inIndex); } - void StdTupleView::Traverse(const Visitor& inVisitor) const + void StdTupleView::Traverse(const Traverser& inVisitor) const { rtti->traverse(ref, inVisitor); } + + void StdTupleView::ConstTraverse(const Traverser& inVisitor) const + { + rtti->constTraverse(ref, inVisitor); + } + + StdVariantView::StdVariantView(const Any& inRef) + : ref(inRef) + { + } + + size_t StdVariantView::TypeNum() const + { + return rtti->TypeNum(); + } + + const TypeInfo* StdVariantView::TypeByIndex(size_t inIndex) const + { + return rtti->TypeByIndex(inIndex); + } + + Any StdVariantView::CreateElement(size_t inIndex) const + { + return rtti->createElement(inIndex); + } + + size_t StdVariantView::Index() const + { + return rtti->index(ref); + } + + Any StdVariantView::GetElement(size_t inIndex) const + { + return rtti->getElement(ref, inIndex); + } + + Any StdVariantView::GetConstElement(size_t inIndex) const + { + return rtti->getConstElement(ref, inIndex); + } + + void StdVariantView::Visit(const Visitor& inVisitor) const + { + rtti->visit(ref, inVisitor); + } + + Any StdVariantView::Emplace(size_t inIndex, const Argument& inTempObj) const + { + return rtti->emplace(ref, inIndex, inTempObj); + } } // namespace Mirror diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index 7c29dfda..7d4b8228 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -1472,12 +1472,12 @@ TEST(AnyTest, StdTupleViewTest) ASSERT_EQ(v0.Get(2).As(), "2"); int count = 0; - v0.Traverse([&](const Any& inRef) -> void { - if (count == 0) { + v0.Traverse([&](const Any& inRef, size_t inIndex) -> void { + if (inIndex == 0) { ASSERT_EQ(inRef.As(), 1); - } else if (count == 1) { + } else if (inIndex == 1) { ASSERT_TRUE(inRef.As()); - } else if (count == 2) { + } else if (inIndex == 2) { ASSERT_EQ(inRef.As(), "2"); } count++; From 71e56e2dd06390c3740be20af1f039198b0385b8 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Mon, 8 Sep 2025 22:57:20 +0800 Subject: [PATCH 04/12] fix: macos web dev server script not start issue --- Script/start_editor_web_dev_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Script/start_editor_web_dev_server.py b/Script/start_editor_web_dev_server.py index b02b73a7..a9e3958e 100644 --- a/Script/start_editor_web_dev_server.py +++ b/Script/start_editor_web_dev_server.py @@ -44,7 +44,7 @@ def start_dev_server(nodejs_root, web_project_root): elif platform.system() == 'Darwin': nodejs_bin = Path(nodejs_root) / 'bin' env['PATH'] = '{}:{}'.format(env['PATH'], nodejs_bin) - subprocess.run(['npm', 'run', 'dev'], shell=True, encoding='utf-8', env=env, cwd=web_project_root) + subprocess.run(['npm', 'run', 'dev'], encoding='utf-8', env=env, cwd=web_project_root) else: raise RuntimeError('Unsupported OS') From 95140626aeef3f874ec4ab50f24b28f5ad8fe41d Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 20 Sep 2025 21:46:33 +0800 Subject: [PATCH 05/12] feat: add a util macro to temporary disable/enable optimizations --- Engine/Source/Common/Include/Common/Debug.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Engine/Source/Common/Include/Common/Debug.h b/Engine/Source/Common/Include/Common/Debug.h index df754bd3..5fc8a85d 100644 --- a/Engine/Source/Common/Include/Common/Debug.h +++ b/Engine/Source/Common/Include/Common/Debug.h @@ -13,6 +13,22 @@ #define QuickFail() Assert(false) #define QuickFailWithReason(reason) AssertWithReason(false, reason) +#if COMPILER_MSVC +#define ENABLE_OPTIMIZATION __pragma(optimize("", on)) +#define DISABLE_OPTIMIZATION __pragma(optimize("", off)) +#elif COMPILER_APPLE_CLANG +#define ENABLE_OPTIMIZATION _Pragma("clang optimize on") +#define DISABLE_OPTIMIZATION _Pragma("clang optimize off") +#endif + +#if !defined(__clang__) + #define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL __pragma(optimize("",off)) + #define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL __pragma(optimize("",on)) +#elif defined(_MSC_VER) // Clang only supports __pragma with -fms-extensions + #define PRAGMA_DISABLE_OPTIMIZATION_ACTUAL __pragma(clang optimize off) + #define PRAGMA_ENABLE_OPTIMIZATION_ACTUAL __pragma(clang optimize on) +#endif + namespace Common { class Debug { public: From bfb426329fc420b63d840e7529809e26caef3ed4 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 20 Sep 2025 22:28:43 +0800 Subject: [PATCH 06/12] fix: shader module not destroyed before device destroy --- Engine/Source/Render/Include/Render/Shader.h | 1 + Engine/Source/Render/Src/Shader.cpp | 6 ++++++ Sample/Rendering-Triangle/Triangle.cpp | 2 ++ 3 files changed, 9 insertions(+) diff --git a/Engine/Source/Render/Include/Render/Shader.h b/Engine/Source/Render/Include/Render/Shader.h index 2d889f6d..015b5fc3 100644 --- a/Engine/Source/Render/Include/Render/Shader.h +++ b/Engine/Source/Render/Include/Render/Shader.h @@ -371,6 +371,7 @@ namespace Render { // render thread ShaderInstance GetShaderInstance(const ShaderType& inShaderType, const ShaderVariantValueMap& inShaderVariants); + void Invalidate(); private: using VariantsShaderModules = std::unordered_map>; diff --git a/Engine/Source/Render/Src/Shader.cpp b/Engine/Source/Render/Src/Shader.cpp index 7bbf8133..d5f64996 100644 --- a/Engine/Source/Render/Src/Shader.cpp +++ b/Engine/Source/Render/Src/Shader.cpp @@ -454,4 +454,10 @@ namespace Render { result.reflectionData = &reflectionData; return result; } + + void ShaderMap::Invalidate() + { + Assert(Core::ThreadContext::IsRenderThread()); + shaderModules.clear(); + } } // namespace Render diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 07109fa6..5e4d5201 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace Common; using namespace Render; @@ -192,6 +193,7 @@ void TriangleApplication::OnDestroy() PipelineCache::Get(*device).Invalidate(); BufferPool::Get(*device).Invalidate(); TexturePool::Get(*device).Invalidate(); + ShaderMap::Get(*device).Invalidate(); }); RenderThread::Get().Flush(); From d02623d7fc4f3cb578e23c702b6fd3e7d5c27975 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 20 Sep 2025 23:15:52 +0800 Subject: [PATCH 07/12] fix: rendering triangle sample display issue on macOS --- Sample/Rendering-Triangle/Triangle.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Sample/Rendering-Triangle/Triangle.cpp b/Sample/Rendering-Triangle/Triangle.cpp index 5e4d5201..9baa375a 100644 --- a/Sample/Rendering-Triangle/Triangle.cpp +++ b/Sample/Rendering-Triangle/Triangle.cpp @@ -62,6 +62,7 @@ class TriangleApplication final : public Application { void CreateDevice(); void CompileAllShaders() const; void FetchShaderInstances(); + void CreateSurface(); void CreateSwapChain(); void CreateTriangleVertexBuffer(); void CreateSyncObjects(); @@ -94,8 +95,12 @@ void TriangleApplication::OnCreate() RenderThread::Get().Start(); RenderWorkerThreads::Get().Start(); + // NOTICE: some platform surface need created on main thread, like NSView* in macOS + // so we create device and surface in main thread early + CreateDevice(); + CreateSurface(); + RenderThread::Get().EmplaceTask([this]() -> void { - CreateDevice(); FetchShaderInstances(); CreateSwapChain(); CreateTriangleVertexBuffer(); @@ -228,6 +233,11 @@ void TriangleApplication::FetchShaderInstances() trianglePS = ShaderMap::Get(*device).GetShaderInstance(TrianglePS::Get(), {}); } +void TriangleApplication::CreateSurface() +{ + surface = device->CreateSurface(SurfaceCreateInfo(GetPlatformWindow())); +} + void TriangleApplication::CreateSwapChain() { static std::vector swapChainFormatQualifiers = { @@ -235,8 +245,6 @@ void TriangleApplication::CreateSwapChain() PixelFormat::bgra8Unorm }; - surface = device->CreateSurface(SurfaceCreateInfo(GetPlatformWindow())); - for (const auto format : swapChainFormatQualifiers) { if (device->CheckSwapChainFormatSupport(surface.Get(), format)) { swapChainFormat = format; From c81ab5e2de5912f107794b52e4fb3371bc79436e Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 20 Sep 2025 23:35:09 +0800 Subject: [PATCH 08/12] feat: add a option to control whether to enable cmake compile commands export --- CMake/Common.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMake/Common.cmake b/CMake/Common.cmake index 8f15a5ef..e8bd3dac 100644 --- a/CMake/Common.cmake +++ b/CMake/Common.cmake @@ -1,9 +1,11 @@ option(BUILD_EDITOR "Build Explosion editor" ON) option(CI "Build in CI" OFF) option(USE_UNITY_BUILD "Use unity build" ON) +option(EXPORT_COMPILE_COMMANDS "Whether to export all compile commands" OFF) set(CMAKE_CXX_STANDARD 20) set(CMAKE_UNITY_BUILD ${USE_UNITY_BUILD}) +set(CMAKE_EXPORT_COMPILE_COMMANDS ${EXPORT_COMPILE_COMMANDS}) get_cmake_property(GENERATOR_IS_MULTI_CONFIG GENERATOR_IS_MULTI_CONFIG) if (${GENERATOR_IS_MULTI_CONFIG}) From 6fe49c0337f4e72b199a164bd2eddd139431a161 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sat, 20 Sep 2025 23:59:50 +0800 Subject: [PATCH 09/12] fix: mirror tool qt framework headers build issue on macOS --- CMake/Target.cmake | 16 +++++++++++++--- Editor/CMakeLists.txt | 2 ++ Tool/MirrorTool/ExeSrc/Main.cpp | 4 +++- Tool/MirrorTool/Include/MirrorTool/Parser.h | 3 ++- Tool/MirrorTool/Src/Parser.cpp | 11 ++++++++++- Tool/MirrorTool/Test/Main.cpp | 4 ++-- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CMake/Target.cmake b/CMake/Target.cmake index c4ce9e99..29b3921b 100644 --- a/CMake/Target.cmake +++ b/CMake/Target.cmake @@ -238,7 +238,7 @@ function(exp_get_target_include_dirs_recurse) endfunction() function(exp_add_mirror_info_source_generation_target) - cmake_parse_arguments(PARAMS "DYNAMIC" "NAME;OUTPUT_SRC;OUTPUT_TARGET_NAME" "SEARCH_DIR;PUBLIC_INC;PRIVATE_INC;LIB" ${ARGN}) + cmake_parse_arguments(PARAMS "DYNAMIC" "NAME;OUTPUT_SRC;OUTPUT_TARGET_NAME" "SEARCH_DIR;PUBLIC_INC;PRIVATE_INC;LIB;FRAMEWORK_DIR" ${ARGN}) if (DEFINED PARAMS_PUBLIC_INC) list(APPEND INC ${PARAMS_PUBLIC_INC}) @@ -262,10 +262,20 @@ function(exp_add_mirror_info_source_generation_target) list(APPEND INC_ARGS "-I") foreach (I ${INC}) get_filename_component(ABSOLUTE_I ${I} ABSOLUTE) - list(APPEND ABSOLUTE_INC ${ABSOLUTE_I}) list(APPEND INC_ARGS ${ABSOLUTE_I}) endforeach() + if (DEFINED PARAMS_FRAMEWORK_DIR) + list(APPEND FWK_DIR ${PARAMS_FRAMEWORK_DIR}) + list(APPEND FWK_DIR_ARGS "-F") + endif () + list(REMOVE_DUPLICATES FWK_DIR) + + foreach (F ${FWK_DIR}) + get_filename_component(ABSOLUTE_F ${F} ABSOLUTE) + list(APPEND FWK_DIR_ARGS ${ABSOLUTE_F}) + endforeach () + if (${PARAMS_DYNAMIC}) list(APPEND DYNAMIC_ARG "-d") endif () @@ -282,7 +292,7 @@ function(exp_add_mirror_info_source_generation_target) add_custom_command( OUTPUT ${OUTPUT_SOURCE} - COMMAND "$" ${DYNAMIC_ARG} "-i" ${INPUT_HEADER_FILE} "-o" ${OUTPUT_SOURCE} ${INC_ARGS} + COMMAND "$" ${DYNAMIC_ARG} "-i" ${INPUT_HEADER_FILE} "-o" ${OUTPUT_SOURCE} ${INC_ARGS} ${FWK_DIR_ARGS} DEPENDS MirrorTool ${INPUT_HEADER_FILE} ) endforeach() diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index 05b9e282..1b746043 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -10,6 +10,7 @@ qt_standard_project_setup(REQUIRES ${QT_VERSION}) if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(PLATFORM_EXECUTABLE_HINT MACOSX_BUNDLE) set(BUNDLE_INSTALL_DESTINATION BUNDLE DESTINATION ${CMAKE_INSTALL_PREFIX}/Engine/Binaries) + set(PLATFORM_FRAMEWORK_DIR ${QT_LIB_PREFIX}/lib) endif () set(EDITOR_INCLUDES Include) @@ -28,6 +29,7 @@ exp_add_mirror_info_source_generation_target( SEARCH_DIR Include PRIVATE_INC ${EDITOR_INCLUDES} LIB ${EDITOR_LIBS} + FRAMEWORK_DIR ${PLATFORM_FRAMEWORK_DIR} ) file(GLOB_RECURSE SOURCES Src/*.cpp) diff --git a/Tool/MirrorTool/ExeSrc/Main.cpp b/Tool/MirrorTool/ExeSrc/Main.cpp index 58cab5ad..5c0e0965 100644 --- a/Tool/MirrorTool/ExeSrc/Main.cpp +++ b/Tool/MirrorTool/ExeSrc/Main.cpp @@ -31,12 +31,14 @@ int main(int argc, char* argv[]) // NOLINT std::string inputFile; std::string outputFile; std::vector headerDirs; + std::vector frameworkDirs; bool dynamic = false; if (const auto cli = ( clipp::required("-i").doc("input header file") & clipp::value("input header file", inputFile), clipp::required("-o").doc("output file") & clipp::value("output file", outputFile), clipp::option("-I").doc("header search dirs") & clipp::values("header search dirs", headerDirs), + clipp::option("-F").doc("framework search dirs") & clipp::values("framework search dirs", frameworkDirs), clipp::option("-d").set(dynamic).doc("used for dynamic library (auto unload some metas)")); !clipp::parse(argc, argv, cli)) { std::cout << clipp::make_man_page(cli, argv[0]); @@ -58,7 +60,7 @@ int main(int argc, char* argv[]) // NOLINT return 1; } - MirrorTool::Parser parser(inputFile, headerDirs); + MirrorTool::Parser parser(inputFile, headerDirs, frameworkDirs); auto [parseSuccess, parseResultOrError] = parser.Parse(); if (!parseSuccess) { diff --git a/Tool/MirrorTool/Include/MirrorTool/Parser.h b/Tool/MirrorTool/Include/MirrorTool/Parser.h index 057b1a83..c298b209 100644 --- a/Tool/MirrorTool/Include/MirrorTool/Parser.h +++ b/Tool/MirrorTool/Include/MirrorTool/Parser.h @@ -94,7 +94,7 @@ namespace MirrorTool { using Result = std::pair>; NonCopyable(Parser) - explicit Parser(std::string inSourceFile, std::vector inHeaderDirs); + explicit Parser(std::string inSourceFile, std::vector inHeaderDirs, std::vector inFrameworkDirs); ~Parser(); Result Parse() const; @@ -105,5 +105,6 @@ namespace MirrorTool { std::string sourceFile; std::vector headerDirs; + std::vector frameworkDirs; }; } diff --git a/Tool/MirrorTool/Src/Parser.cpp b/Tool/MirrorTool/Src/Parser.cpp index d779fd71..38518e57 100644 --- a/Tool/MirrorTool/Src/Parser.cpp +++ b/Tool/MirrorTool/Src/Parser.cpp @@ -413,7 +413,10 @@ namespace MirrorTool { } namespace MirrorTool { - Parser::Parser(std::string inSourceFile, std::vector inHeaderDirs) : sourceFile(std::move(inSourceFile)), headerDirs(std::move(inHeaderDirs)) + Parser::Parser(std::string inSourceFile, std::vector inHeaderDirs, std::vector inFrameworkDirs) + : sourceFile(std::move(inSourceFile)) + , headerDirs(std::move(inHeaderDirs)) + , frameworkDirs(std::move(inFrameworkDirs)) { } @@ -451,6 +454,12 @@ namespace MirrorTool { for (const std::string& headerDir : headerDirs) { argumentStrs.emplace_back(std::string("-I") + headerDir); } +#if PLATFORM_MACOS + for (const std::string& frameworkDir : frameworkDirs) { + argumentStrs.emplace_back("-iframework"); + argumentStrs.emplace_back(frameworkDir); + } +#endif std::vector arguments(argumentStrs.size()); for (auto i = 0; i < arguments.size(); i++) { diff --git a/Tool/MirrorTool/Test/Main.cpp b/Tool/MirrorTool/Test/Main.cpp index 5d4bb9d2..cb0eaaa3 100644 --- a/Tool/MirrorTool/Test/Main.cpp +++ b/Tool/MirrorTool/Test/Main.cpp @@ -120,7 +120,7 @@ void AssertNamespaceInfoEqual(const NamespaceInfo& lhs, const NamespaceInfo& rhs TEST(MirrorTest, ParserTest) { - const Parser parser("../Test/Resource/Mirror/MirrorToolInput.h", { "../Test/Resource/Mirror" }); + const Parser parser("../Test/Resource/Mirror/MirrorToolInput.h", { "../Test/Resource/Mirror" }, {}); auto [parseSuccess, parseResultOrError] = parser.Parse(); ASSERT_TRUE(parseSuccess); @@ -160,7 +160,7 @@ TEST(MirrorTest, ParserTest) TEST(MirrorTest, GeneratorTest) { - const Parser parser("../Test/Resource/Mirror/MirrorToolInput.h", { "../Test/Resource/Mirror" }); + const Parser parser("../Test/Resource/Mirror/MirrorToolInput.h", { "../Test/Resource/Mirror" }, {}); auto [parseSuccess, parseResultOrError] = parser.Parse(); ASSERT_TRUE(parseSuccess); From e9945322cc31e41edf8f23f706431ced2e4c1f58 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 21 Sep 2025 00:29:54 +0800 Subject: [PATCH 10/12] fix: Qt build on macOS 26 caused by AGL lib missing --- ThirdParty/CMakeLists.txt | 5 ++ .../Qt-Darwin-6.9.1-FindWrapOpenGL.cmake | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 ThirdParty/Patch/Qt-Darwin-6.9.1-FindWrapOpenGL.cmake diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 7a3559ea..0d43e733 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -267,6 +267,11 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/msvc2022_64 CACHE PATH "" FORCE) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/macos CACHE PATH "" FORCE) + + # NOTICE: Fix Qt 6.9.1 build on macOS 26, #see https://codereview.qt-project.org/c/qt/qtbase/+/652022/3/cmake/FindWrapOpenGL.cmake#b50 + if (QT_VERSION STREQUAL "6.9.1") + file(COPY_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Patch/Qt-Darwin-6.9.1-FindWrapOpenGL.cmake ${QT_LIB_PREFIX}/lib/cmake/Qt6/FindWrapOpenGL.cmake) + endif () endif () # rapidjson diff --git a/ThirdParty/Patch/Qt-Darwin-6.9.1-FindWrapOpenGL.cmake b/ThirdParty/Patch/Qt-Darwin-6.9.1-FindWrapOpenGL.cmake new file mode 100644 index 00000000..fe73ab78 --- /dev/null +++ b/ThirdParty/Patch/Qt-Darwin-6.9.1-FindWrapOpenGL.cmake @@ -0,0 +1,57 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# We can't create the same interface imported target multiple times, CMake will complain if we do +# that. This can happen if the find_package call is done in multiple different subdirectories. +if(TARGET WrapOpenGL::WrapOpenGL) + set(WrapOpenGL_FOUND ON) + return() +endif() + +set(WrapOpenGL_FOUND OFF) + +find_package(OpenGL ${WrapOpenGL_FIND_VERSION}) + +if (OpenGL_FOUND) + set(WrapOpenGL_FOUND ON) + + add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED) + if(APPLE) + # CMake 3.27 and older: + # On Darwin platforms FindOpenGL sets IMPORTED_LOCATION to the absolute path of the library + # within the framework. This ends up as an absolute path link flag, which we don't want, + # because that makes our .prl files un-relocatable. + # Extract the framework path instead, and use that in INTERFACE_LINK_LIBRARIES, + # which CMake ends up transforming into a relocatable -framework flag. + # See https://gitlab.kitware.com/cmake/cmake/-/issues/20871 for details. + # + # CMake 3.28 and above: + # IMPORTED_LOCATION is the absolute path the the OpenGL.framework folder. + get_target_property(__opengl_fw_lib_path OpenGL::GL IMPORTED_LOCATION) + if(__opengl_fw_lib_path AND NOT __opengl_fw_lib_path MATCHES "/([^/]+)\\.framework$") + get_filename_component(__opengl_fw_path "${__opengl_fw_lib_path}" DIRECTORY) + endif() + + if(NOT __opengl_fw_path) + # Just a safety measure in case if no OpenGL::GL target exists. + set(__opengl_fw_path "-framework OpenGL") + endif() + + target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE ${__opengl_fw_path}) + else() + target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE OpenGL::GL) + endif() +elseif(UNIX AND NOT APPLE AND NOT CMAKE_SYSTEM_NAME STREQUAL "Integrity") + # Requesting only the OpenGL component ensures CMake does not mark the package as + # not found if neither GLX nor libGL are available. This allows finding OpenGL + # on an X11-less Linux system. + find_package(OpenGL ${WrapOpenGL_FIND_VERSION} COMPONENTS OpenGL) + if (OpenGL_FOUND) + set(WrapOpenGL_FOUND ON) + add_library(WrapOpenGL::WrapOpenGL INTERFACE IMPORTED) + target_link_libraries(WrapOpenGL::WrapOpenGL INTERFACE OpenGL::OpenGL) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WrapOpenGL DEFAULT_MSG WrapOpenGL_FOUND) From dc85650fc4219c00a28661e8b4c346a4bc819c75 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 21 Sep 2025 00:33:37 +0800 Subject: [PATCH 11/12] fix: mirror header --- Engine/Source/Mirror/Include/Mirror/Mirror.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Engine/Source/Mirror/Include/Mirror/Mirror.h b/Engine/Source/Mirror/Include/Mirror/Mirror.h index 5ef823c1..58731a7c 100644 --- a/Engine/Source/Mirror/Include/Mirror/Mirror.h +++ b/Engine/Source/Mirror/Include/Mirror/Mirror.h @@ -22,8 +22,6 @@ #include #include #include -#include -#include #if COMPILER_MSVC #define functionSignature __FUNCSIG__ From b9656977602e52b6c7ccb9d19f01523bef19e3d4 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 21 Sep 2025 00:39:57 +0800 Subject: [PATCH 12/12] fix: any test --- Engine/Source/Mirror/Test/AnyTest.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Engine/Source/Mirror/Test/AnyTest.cpp b/Engine/Source/Mirror/Test/AnyTest.cpp index 7d4b8228..35197721 100644 --- a/Engine/Source/Mirror/Test/AnyTest.cpp +++ b/Engine/Source/Mirror/Test/AnyTest.cpp @@ -122,13 +122,6 @@ TEST(AnyTest, DefaultCtorTest) TEST(AnyTest, DetorTest) { bool live = false; - { - Any a0 = AnyDtorTest(live); - ASSERT_TRUE(live); - } - ASSERT_FALSE(live); - - live = false; { AnyDtorTest obj(live, true); // NOLINT {