From a97c0de6c1128fa99961684cd9c1366ed5bd0291 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Sat, 28 Jun 2025 17:02:30 +0800 Subject: [PATCH 1/4] feat: update float input --- Editor/Qml/EFloatInput.qml | 22 +++++++++++++++++----- Editor/Qml/EWidgetSamples.qml | 6 +----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Editor/Qml/EFloatInput.qml b/Editor/Qml/EFloatInput.qml index eb4251054..c2dacec42 100644 --- a/Editor/Qml/EFloatInput.qml +++ b/Editor/Qml/EFloatInput.qml @@ -2,15 +2,27 @@ import QtQuick import QtQuick.Controls import QtQuick.Controls.Basic -ETextField { +Item { + property double value: 0.0 property double from: 0.0 property double to: 1.0 id: root - implicitWidth: 100 + implicitWidth: textField.implicitWidth + implicitHeight: textField.implicitHeight - validator: DoubleValidator { - bottom: root.from - top: root.to + ETextField { + id: textField + implicitWidth: 100 + text: value + + onAccepted: { + root.value = Number(text) + } + + validator: DoubleValidator { + bottom: root.from + top: root.to + } } } diff --git a/Editor/Qml/EWidgetSamples.qml b/Editor/Qml/EWidgetSamples.qml index 24014e122..52fea59fa 100644 --- a/Editor/Qml/EWidgetSamples.qml +++ b/Editor/Qml/EWidgetSamples.qml @@ -449,11 +449,7 @@ Rectangle { Layout.margins: 5 RowLayout { - EFloatInput { - onAccepted: { - console.log('value accepted, value=' + text) - } - } + EFloatInput {} EText { Layout.leftMargin: 5 From 64269da9956f0894716fe5478894d9854c749f94 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Tue, 8 Jul 2025 21:41:26 +0800 Subject: [PATCH 2/4] feat: material shader types build --- Engine/Shader/BasePassPS.esl | 0 Engine/Shader/BasePassVS.esl | 0 Engine/Source/Common/Include/Common/File.h | 1 + Engine/Source/Common/Src/File.cpp | 14 +++ Engine/Source/Common/Test/FileTest.cpp | 16 +++ Engine/Source/Render/Include/Render/Shader.h | 2 +- Engine/Source/Render/Src/Shader.cpp | 6 +- .../Runtime/Include/Runtime/Asset/Material.h | 10 ++ Engine/Source/Runtime/Src/Asset/Material.cpp | 100 ++++++++++++++++++ 9 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 Engine/Shader/BasePassPS.esl create mode 100644 Engine/Shader/BasePassVS.esl create mode 100644 Engine/Source/Common/Test/FileTest.cpp diff --git a/Engine/Shader/BasePassPS.esl b/Engine/Shader/BasePassPS.esl new file mode 100644 index 000000000..e69de29bb diff --git a/Engine/Shader/BasePassVS.esl b/Engine/Shader/BasePassVS.esl new file mode 100644 index 000000000..e69de29bb diff --git a/Engine/Source/Common/Include/Common/File.h b/Engine/Source/Common/Include/Common/File.h index 65f808d25..bb6855910 100644 --- a/Engine/Source/Common/Include/Common/File.h +++ b/Engine/Source/Common/Include/Common/File.h @@ -12,6 +12,7 @@ namespace Common { class FileUtils { public: static std::string ReadTextFile(const std::string& inFileName); + static void WriteTextFile(const std::string& inFileName, const std::string& inContent); static rapidjson::Document ReadJsonFile(const std::string& inFileName); static void WriteJsonFile(const std::string& inFileName, const rapidjson::Document& inJsonDocument, bool inPretty = true); }; diff --git a/Engine/Source/Common/Src/File.cpp b/Engine/Source/Common/Src/File.cpp index 9300dece1..5b3255e2a 100644 --- a/Engine/Source/Common/Src/File.cpp +++ b/Engine/Source/Common/Src/File.cpp @@ -30,6 +30,20 @@ namespace Common { return result; } + void FileUtils::WriteTextFile(const std::string& inFileName, const std::string& inContent) + { + const Path path(inFileName); + if (const Path parentPath = path.Parent(); + !parentPath.Exists()) { + parentPath.MakeDir(); + } + + std::ofstream file(inFileName, std::ios::out | std::ios::binary | std::ios::trunc); + Assert(file.is_open()); + file.write(inContent.data(), static_cast(inContent.size())); + file.close(); + } + rapidjson::Document FileUtils::ReadJsonFile(const std::string& inFileName) { char buffer[65536]; diff --git a/Engine/Source/Common/Test/FileTest.cpp b/Engine/Source/Common/Test/FileTest.cpp new file mode 100644 index 000000000..8e14fba1c --- /dev/null +++ b/Engine/Source/Common/Test/FileTest.cpp @@ -0,0 +1,16 @@ +// +// Created by johnk on 2025/7/8. +// + +#include +#include +#include + +TEST(FileTest, ReadWriteTextFileTest) +{ + static Common::Path file = "../Test/Generated/Common/ReadTextFileTest.txt"; + + Common::FileUtils::WriteTextFile(file.Absolute().String(), "hello"); + const std::string content = Common::FileUtils::ReadTextFile(file.Absolute().String()); + ASSERT_EQ(content, "hello"); +} diff --git a/Engine/Source/Render/Include/Render/Shader.h b/Engine/Source/Render/Include/Render/Shader.h index 888453299..2d889f6d2 100644 --- a/Engine/Source/Render/Include/Render/Shader.h +++ b/Engine/Source/Render/Include/Render/Shader.h @@ -259,7 +259,7 @@ namespace Render { class MaterialShaderType final : public ShaderType { public: MaterialShaderType( - const VertexFactoryType& inVertexFactory, + const VertexFactoryType& inVertexFactoryType, std::string inName, RHI::ShaderStageBits inStage, std::string inSourceFile, diff --git a/Engine/Source/Render/Src/Shader.cpp b/Engine/Source/Render/Src/Shader.cpp index ca8260dc5..7bbf81335 100644 --- a/Engine/Source/Render/Src/Shader.cpp +++ b/Engine/Source/Render/Src/Shader.cpp @@ -244,7 +244,7 @@ namespace Render { } MaterialShaderType::MaterialShaderType( - const VertexFactoryType& inVertexFactory, + const VertexFactoryType& inVertexFactoryType, std::string inName, RHI::ShaderStageBits inStage, std::string inSourceFile, @@ -252,13 +252,13 @@ namespace Render { const std::vector& inIncludeDirectories, const ShaderVariantFieldVec& inShaderVariantFields) : ShaderType(Internal::MakeTypeKeyFromName(inName)) - , vertexFactory(inVertexFactory) + , vertexFactory(inVertexFactoryType) , name(std::move(inName)) , stage(inStage) , sourceFile(std::move(inSourceFile)) , entryPoint(std::move(inEntryPoint)) , includeDirectories(inIncludeDirectories) - , shaderVariantFields(Common::VectorUtils::Combine(inVertexFactory.GetVariantFields(), inShaderVariantFields)) + , shaderVariantFields(Common::VectorUtils::Combine(inVertexFactoryType.GetVariantFields(), inShaderVariantFields)) { } diff --git a/Engine/Source/Runtime/Include/Runtime/Asset/Material.h b/Engine/Source/Runtime/Include/Runtime/Asset/Material.h index 356c11762..b0420bdd3 100644 --- a/Engine/Source/Runtime/Include/Runtime/Asset/Material.h +++ b/Engine/Source/Runtime/Include/Runtime/Asset/Material.h @@ -20,6 +20,7 @@ namespace Runtime { postProcess, max }; + static_assert(static_cast(MaterialType::max) == static_cast(Render::MaterialType::max)); struct RUNTIME_API EClass() MaterialBoolVariantField { EClassBody(MaterialBoolVariantField) @@ -151,6 +152,9 @@ namespace Runtime { explicit Material(Core::Uri inUri); + NonCopyable(Material) + NonMovable(Material) + EFunc() MaterialType GetType() const; EFunc() void SetType(MaterialType inType); EFunc() const std::string& GetSource() const; @@ -174,11 +178,17 @@ namespace Runtime { EFunc() const ParameterFieldMap& GetParameterFields() const; EFunc() ParameterField& EmplaceParameterField(const std::string& inName); + EFunc() void Update(); + private: + using StageShaderTypeMap = std::unordered_map>; + EProperty() MaterialType type; EProperty() std::string source; EProperty() VariantFieldMap variantFields; EProperty() ParameterFieldMap parameterFields; + + std::unordered_map shaderTypes; }; class RUNTIME_API EClass() MaterialInstance final : public Asset { diff --git a/Engine/Source/Runtime/Src/Asset/Material.cpp b/Engine/Source/Runtime/Src/Asset/Material.cpp index ac6c71059..da4c5d075 100644 --- a/Engine/Source/Runtime/Src/Asset/Material.cpp +++ b/Engine/Source/Runtime/Src/Asset/Material.cpp @@ -4,6 +4,52 @@ #include +namespace Runtime::Internal { + static std::string GetVariantFieldMacro(const std::string& inVariantFieldName) + { + return Common::StringUtils::ToUpperCase(std::format("MATERIAL_VARIANT_{}", inVariantFieldName)); + } + + template + struct VariantFieldConverter {}; + + template <> + struct VariantFieldConverter { + static Render::ShaderBoolVariantField Execute(const std::string& inVariantFieldName, const MaterialBoolVariantField& inVariantField) + { + return { + GetVariantFieldMacro(inVariantFieldName), + inVariantField.defaultValue + }; + } + }; + + template <> + struct VariantFieldConverter { + static Render::ShaderRangedIntVariantField Execute(const std::string& inVariantFieldName, const MaterialRangedUintVariantField& inVariantField) + { + return { + GetVariantFieldMacro(inVariantFieldName), + inVariantField.defaultValue, + inVariantField.range + }; + } + }; + + static Render::ShaderVariantFieldVec BuildShaderVariantFieldVec(const Material::VariantFieldMap& inVariantFields) + { + Render::ShaderVariantFieldVec result; + result.reserve(inVariantFields.size()); + + for (const auto& [variantFieldName, variantField] : inVariantFields) { + std::visit([&](const T& inTypedVariantField) -> void { + result.emplace_back(VariantFieldConverter::Execute(variantFieldName, inTypedVariantField)); + }, variantField); + } + return result; + } +} + namespace Runtime { MaterialBoolVariantField::MaterialBoolVariantField() : defaultValue(false) @@ -178,6 +224,60 @@ namespace Runtime { return parameterFields.at(inName); } + void Material::Update() + { + static std::unordered_set supportedStages = { + RHI::ShaderStageBits::sVertex, + RHI::ShaderStageBits::sPixel}; + static std::unordered_map stageEntrySourceFileMap = { + {RHI::ShaderStageBits::sVertex, "Engine/Shader/BasePassVS.esl"}, + {RHI::ShaderStageBits::sPixel, "Engine/Shader/BasePassPS.esl"}}; + static std::unordered_map stageSimpleNameMap = { + {RHI::ShaderStageBits::sVertex, "VS"}, + {RHI::ShaderStageBits::sPixel, "PS"}}; + static std::unordered_map stageEntryPointMap = { + {RHI::ShaderStageBits::sVertex, "VSMain"}, + {RHI::ShaderStageBits::sPixel, "PSMain"}}; + + const std::string uriStr = Uri().Str(); + const std::string materialName = Common::Path(Uri().Content()).FileNameWithoutExtension(); + const std::uint64_t uriHash = Common::HashUtils::CityHash(uriStr.c_str(), uriStr.size()); + const Common::Path materialRootCacheDir = std::format("Game/Cache/Materials/{}", uriHash); + const Common::Path materialHintFile = materialRootCacheDir / materialName; + const Common::Path materialHeader = materialRootCacheDir / "Material.ush"; + + if (const Common::Path absoluteMaterialRootCacheDir = Core::Paths::Translate(materialRootCacheDir); + !absoluteMaterialRootCacheDir.Exists()) { + absoluteMaterialRootCacheDir.MakeDir(); + } + Common::FileUtils::WriteTextFile(Core::Paths::Translate(materialHintFile).Absolute().String(), ""); + Common::FileUtils::WriteTextFile(Core::Paths::Translate(materialHeader).Absolute().String(), source); + + shaderTypes.clear(); + for (const Render::VertexFactoryType* vertexFactoryType : Render::VertexFactoryTypeRegistry::Get().AllTypes()) { + if (!vertexFactoryType->SupportMaterialType(static_cast(type))) { + continue; + } + + const auto vertexFactoryTypeKey = vertexFactoryType->GetKey(); + shaderTypes.emplace(vertexFactoryTypeKey, StageShaderTypeMap {}); + StageShaderTypeMap& stageShaderTypeMap = shaderTypes.at(vertexFactoryTypeKey); + + for (const auto stage : supportedStages) { + stageShaderTypeMap.emplace( + stage, + Common::MakeUnique( + *vertexFactoryType, + std::format("{}-{}", materialName, stageSimpleNameMap.at(stage)), + stage, + stageEntrySourceFileMap.at(stage), + stageEntryPointMap.at(stage), + std::vector {materialRootCacheDir.String()}, + Internal::BuildShaderVariantFieldVec(variantFields))); + } + } + } + MaterialInstance::MaterialInstance(Core::Uri inUri) : Asset(std::move(inUri)) { From 4d4b222ff9314dbe89a2bf10182f0a9fd89433a8 Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Thu, 17 Jul 2025 21:00:52 +0800 Subject: [PATCH 3/4] fix: float input value binding issue --- Editor/Qml/EFloatInput.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Qml/EFloatInput.qml b/Editor/Qml/EFloatInput.qml index c2dacec42..99710a704 100644 --- a/Editor/Qml/EFloatInput.qml +++ b/Editor/Qml/EFloatInput.qml @@ -3,7 +3,7 @@ import QtQuick.Controls import QtQuick.Controls.Basic Item { - property double value: 0.0 + property double value: Number(textField.text) property double from: 0.0 property double to: 1.0 @@ -17,7 +17,7 @@ Item { text: value onAccepted: { - root.value = Number(text) + root.value = Number(displayText) } validator: DoubleValidator { From a9b2beccb4ff7a88a55f76d696e77c64c0091c2e Mon Sep 17 00:00:00 2001 From: FlyAndNotDown Date: Sat, 19 Jul 2025 13:10:57 +0800 Subject: [PATCH 4/4] refactor: use external file instead qrc protocol to save resource files --- Editor/CMakeLists.txt | 10 ++++------ Editor/Qml/EIcon.qml | 2 +- Editor/Qml/ETheme.qml | 4 ++-- Editor/Src/Widget/QmlWidget.cpp | 4 ++++ 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Editor/CMakeLists.txt b/Editor/CMakeLists.txt index da68c6a5c..3264de357 100644 --- a/Editor/CMakeLists.txt +++ b/Editor/CMakeLists.txt @@ -54,7 +54,6 @@ set(EDITOR_RESOURCE_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/Qml/Resource) get_filename_component(EDITOR_RESOURCE_ROOT_ABSOLUTE ${EDITOR_RESOURCE_ROOT} ABSOLUTE) file(GLOB QML_SOURCES ${EDITOR_QML_ROOT}/*.qml) -file(GLOB_RECURSE RESOURCES ${EDITOR_RESOURCE_ROOT}/*) list( APPEND SINGLETON_QML_SOURCES @@ -70,17 +69,16 @@ foreach (QML_SOURCE ${QML_SOURCES}) endif () endforeach () -foreach (RESOURCE ${RESOURCES}) - string(REPLACE ${EDITOR_RESOURCE_ROOT_ABSOLUTE} "Resource" ALIAS ${RESOURCE}) - set_source_files_properties(${RESOURCE} PROPERTIES QT_RESOURCE_ALIAS ${ALIAS}) -endforeach () +add_custom_command( + TARGET Editor POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${EDITOR_RESOURCE_ROOT_ABSOLUTE} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../Resource +) qt_add_qml_module( Editor NO_CACHEGEN URI editor QML_FILES ${QML_SOURCES} - RESOURCES ${RESOURCES} OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Generated/QmlModule ) # ---- end qml --------------------------------------------------------------------------------------- diff --git a/Editor/Qml/EIcon.qml b/Editor/Qml/EIcon.qml index d14da8cf6..02595f915 100644 --- a/Editor/Qml/EIcon.qml +++ b/Editor/Qml/EIcon.qml @@ -11,7 +11,7 @@ Item { Image { id: imageWidget - source: root.name === '' ? '' : 'Resource/Icon/%1.svg'.arg(root.name) + source: root.name === '' ? '' : 'file:../Resource/Icon/%1.svg'.arg(root.name) sourceSize.width: root.size sourceSize.height: root.size layer.enabled: true diff --git a/Editor/Qml/ETheme.qml b/Editor/Qml/ETheme.qml index 6bcba1614..e6cb6e15c 100644 --- a/Editor/Qml/ETheme.qml +++ b/Editor/Qml/ETheme.qml @@ -18,8 +18,8 @@ QtObject { property color placeHolderFontColor: Qt.color('#c0c3c4') property color linkFontColor: Qt.color('#91b9c4') - property FontLoader normalFont: FontLoader { source: Qt.url('Resource/Font/MiSans-Medium.ttf') } - property FontLoader boldFont: FontLoader { source: Qt.url('Resource/Font/MiSans-Semibold.ttf') } + property FontLoader normalFont: FontLoader { source: 'file:%1/Font/MiSans-Medium.ttf'.arg(appResDir) } + property FontLoader boldFont: FontLoader { source: 'file:%1/Font/MiSans-Semibold.ttf'.arg(appResDir) } property int tiele1FontSize: 20 property int title2FontSize: 18 property int title3FontSize: 16 diff --git a/Editor/Src/Widget/QmlWidget.cpp b/Editor/Src/Widget/QmlWidget.cpp index 840d44c6b..b21e267c7 100644 --- a/Editor/Src/Widget/QmlWidget.cpp +++ b/Editor/Src/Widget/QmlWidget.cpp @@ -2,6 +2,7 @@ // Created by Kindem on 2024/12/31. // +#include #include #include @@ -15,6 +16,9 @@ namespace Editor { , url(QmlEngine::Get().GetUrlFromShort(shortQmlFileName)) , quickView(new QQuickView) { + + const Common::Path resDir = Core::Paths::EngineResDir(); + quickView->rootContext()->setContextProperty("appResDir", QString::fromStdString(resDir.String())); quickView->setResizeMode(QQuickView::SizeRootObjectToView); quickView->setSource(url);