From 843f8df33c7a41903afc88028b60e1b5778ccf64 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Fri, 13 Dec 2024 19:43:29 +0800 Subject: [PATCH 01/12] feat: new gameplay framework --- Editor/Source/Include/Editor/EditorModule.h | 5 +- Editor/Source/Src/EditorModule.cpp | 5 +- .../Include/Common/{Event.h => Delegate.h} | 48 +-- Engine/Source/Common/Src/Event.cpp | 5 - .../Test/{EventTest.cpp => DelegateTest.cpp} | 4 +- Engine/Source/Common/Test/SerializationTest.h | 6 - Engine/Source/RHI/Include/RHI/Instance.h | 3 +- Engine/Source/RHI/Src/Instance.cpp | 12 +- Engine/Source/Runtime/Include/Runtime/ECS.h | 369 +++++++++++------- .../Source/Runtime/Include/Runtime/Engine.h | 6 +- Engine/Source/Runtime/Include/Runtime/World.h | 12 +- Engine/Source/Runtime/Src/ECS.cpp | 146 +++---- Engine/Source/Runtime/Src/Engine.cpp | 10 +- Engine/Source/Runtime/Src/World.cpp | 1 + Engine/Source/Runtime/Test/ECSTest.cpp | 350 ++++++++++++++++- Engine/Source/Runtime/Test/ECSTest.h | 60 +++ .../Source/Runtime/Test/RuntimeTestModule.cpp | 4 +- .../Source/Runtime/Test/RuntimeTestModule.h | 5 +- Engine/Source/Runtime/Test/WorldTest.cpp | 121 ++++++ Engine/Source/Runtime/Test/WorldTest.h | 50 +++ Sample/Base/Application.cpp | 2 +- 21 files changed, 917 insertions(+), 307 deletions(-) rename Engine/Source/Common/Include/Common/{Event.h => Delegate.h} (69%) delete mode 100644 Engine/Source/Common/Src/Event.cpp rename Engine/Source/Common/Test/{EventTest.cpp => DelegateTest.cpp} (92%) create mode 100644 Engine/Source/Runtime/Test/WorldTest.cpp create mode 100644 Engine/Source/Runtime/Test/WorldTest.h diff --git a/Editor/Source/Include/Editor/EditorModule.h b/Editor/Source/Include/Editor/EditorModule.h index a01d8d68c..3caee2ee2 100644 --- a/Editor/Source/Include/Editor/EditorModule.h +++ b/Editor/Source/Include/Editor/EditorModule.h @@ -7,13 +7,10 @@ #include namespace Editor { - class EditorModule final : public Runtime::IGameModule { + class EditorModule final : public Runtime::IEngineModule { public: void OnUnload() override; ::Core::ModuleType Type() const override; Runtime::Engine* CreateEngine(const Runtime::EngineInitParams&) override; - - private: - Common::UniqueRef engine; }; } diff --git a/Editor/Source/Src/EditorModule.cpp b/Editor/Source/Src/EditorModule.cpp index dd0737c69..bd5c810e6 100644 --- a/Editor/Source/Src/EditorModule.cpp +++ b/Editor/Source/Src/EditorModule.cpp @@ -9,7 +9,6 @@ namespace Editor { void EditorModule::OnUnload() { Runtime::EngineHolder::Unload(); - engine.Reset(); } ::Core::ModuleType EditorModule::Type() const @@ -19,9 +18,7 @@ namespace Editor { Runtime::Engine* EditorModule::CreateEngine(const Runtime::EngineInitParams& inParams) { - Assert(engine == nullptr); - engine = new EditorEngine(inParams); - return engine.Get(); + return new EditorEngine(inParams); } } diff --git a/Engine/Source/Common/Include/Common/Event.h b/Engine/Source/Common/Include/Common/Delegate.h similarity index 69% rename from Engine/Source/Common/Include/Common/Event.h rename to Engine/Source/Common/Include/Common/Delegate.h index cf8db02d0..ed48b6cdb 100644 --- a/Engine/Source/Common/Include/Common/Event.h +++ b/Engine/Source/Common/Include/Common/Delegate.h @@ -29,41 +29,41 @@ namespace Common::Internal { } namespace Common { - using ReceiverHandle = size_t; + using CallbackHandle = size_t; template - class Event { + class Delegate { public: - Event(); + Delegate(); - template ReceiverHandle BindStatic(); - template ReceiverHandle BindMember(C& inObj); - template ReceiverHandle BindLambda(F&& inLambda); + template CallbackHandle BindStatic(); + template CallbackHandle BindMember(C& inObj); + template CallbackHandle BindLambda(F&& inLambda); template void Broadcast(Args&&... inArgs) const; - void Unbind(ReceiverHandle inHandle); - size_t ReceiversCount() const; + void Unbind(CallbackHandle inHandle); + size_t Count() const; void Reset(); private: - template void BindStaticInternal(ReceiverHandle inHandle, std::index_sequence); - template void BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence); - template void BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence); + template void BindStaticInternal(CallbackHandle inHandle, std::index_sequence); + template void BindMemberInternal(CallbackHandle inHandle, C& inObj, std::index_sequence); + template void BindLambdaInternal(CallbackHandle inHandle, F&& inLambda, std::index_sequence); - ReceiverHandle counter; - std::vector>> receivers; + CallbackHandle counter; + std::vector>> receivers; }; } namespace Common { template - Event::Event() + Delegate::Delegate() : counter(0) { } template template - ReceiverHandle Event::BindStatic() + CallbackHandle Delegate::BindStatic() { const auto handle = counter++; BindStaticInternal(handle, std::make_index_sequence()); @@ -72,7 +72,7 @@ namespace Common { template template - ReceiverHandle Event::BindMember(C& inObj) + CallbackHandle Delegate::BindMember(C& inObj) { const auto handle = counter++; BindMemberInternal(handle, inObj, std::make_index_sequence()); @@ -81,7 +81,7 @@ namespace Common { template template - ReceiverHandle Event::BindLambda(F&& inLambda) + CallbackHandle Delegate::BindLambda(F&& inLambda) { const auto handle = counter++; BindLambdaInternal(handle, std::forward(inLambda), std::make_index_sequence()); @@ -90,7 +90,7 @@ namespace Common { template template - void Event::Broadcast(Args&&... inArgs) const + void Delegate::Broadcast(Args&&... inArgs) const { for (const auto& [_, receiver] : receivers) { receiver(std::forward(inArgs)...); @@ -98,7 +98,7 @@ namespace Common { } template - void Event::Unbind(ReceiverHandle inHandle) + void Delegate::Unbind(CallbackHandle inHandle) { auto iter = std::find_if(receivers.begin(), receivers.end(), [&](const auto& pair) -> bool { return pair.first == inHandle; }); Assert(iter != receivers.end()); @@ -106,13 +106,13 @@ namespace Common { } template - size_t Event::ReceiversCount() const + size_t Delegate::Count() const { return receivers.size(); } template - void Event::Reset() + void Delegate::Reset() { counter = 0; receivers.clear(); @@ -120,21 +120,21 @@ namespace Common { template template - void Event::BindStaticInternal(ReceiverHandle inHandle, std::index_sequence) + void Delegate::BindStaticInternal(CallbackHandle inHandle, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(F, Internal::IndexToStdPlaceholder::value...)); } template template - void Event::BindMemberInternal(ReceiverHandle inHandle, C& inObj, std::index_sequence) + void Delegate::BindMemberInternal(CallbackHandle inHandle, C& inObj, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(F, &inObj, Internal::IndexToStdPlaceholder::value...)); } template template - void Event::BindLambdaInternal(ReceiverHandle inHandle, F&& inLambda, std::index_sequence) + void Delegate::BindLambdaInternal(CallbackHandle inHandle, F&& inLambda, std::index_sequence) { receivers.emplace_back(inHandle, std::bind(inLambda, Internal::IndexToStdPlaceholder::value...)); } diff --git a/Engine/Source/Common/Src/Event.cpp b/Engine/Source/Common/Src/Event.cpp deleted file mode 100644 index 84430caec..000000000 --- a/Engine/Source/Common/Src/Event.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by johnk on 2024/11/5. -// - -#include diff --git a/Engine/Source/Common/Test/EventTest.cpp b/Engine/Source/Common/Test/DelegateTest.cpp similarity index 92% rename from Engine/Source/Common/Test/EventTest.cpp rename to Engine/Source/Common/Test/DelegateTest.cpp index fd94a5da3..97d6a948a 100644 --- a/Engine/Source/Common/Test/EventTest.cpp +++ b/Engine/Source/Common/Test/DelegateTest.cpp @@ -2,7 +2,7 @@ // Created by johnk on 2024/11/5. // -#include +#include static int counter = 0; @@ -29,7 +29,7 @@ TEST(EventTest, BasicTest) { Receiver receiver; - Event event; + Delegate event; ASSERT_EQ(event.BindStatic<&StaticReceiver>(), 0); ASSERT_EQ(event.BindMember<&Receiver::Receive>(receiver), 1); ASSERT_EQ(event.BindLambda([](int a, bool b) -> void { diff --git a/Engine/Source/Common/Test/SerializationTest.h b/Engine/Source/Common/Test/SerializationTest.h index fe394e874..706fe3327 100644 --- a/Engine/Source/Common/Test/SerializationTest.h +++ b/Engine/Source/Common/Test/SerializationTest.h @@ -11,7 +11,6 @@ #include #include #include -#include inline std::string FltToJson(float value) { @@ -36,7 +35,6 @@ inline std::string GetEndianString(std::endian e) template void PerformTypedSerializationTestWithStream( - const std::string& contextString, const std::function()>& createSerializeStream, const std::function()>& createDeserializeStream, const T& inValue) @@ -50,8 +48,6 @@ void PerformTypedSerializationTestWithStream( T value; const auto stream = createDeserializeStream(); Common::Deserialize(*stream, value); - - std::cout << "PerformTypedSerializationTestWithStream, context: " << contextString << std::endl; ASSERT_EQ(inValue, value); } } @@ -63,14 +59,12 @@ void PerformTypedSerializationTestWithEndian(const T& inValue) std::filesystem::create_directories(fileName.parent_path()); PerformTypedSerializationTestWithStream( - std::format("BinaryFile<{}, {}>", typeid(T).name(), GetEndianString(E)), []() -> Common::UniqueRef { return { new Common::BinaryFileSerializeStream(fileName.string()) }; }, []() -> Common::UniqueRef { return { new Common::BinaryFileDeserializeStream(fileName.string()) }; }, inValue); std::vector buffer; PerformTypedSerializationTestWithStream( - std::format("Memory<{}, {}>", typeid(T).name(), GetEndianString(E)), [&]() -> Common::UniqueRef { return { new Common::MemorySerializeStream(buffer) }; }, [&]() -> Common::UniqueRef { return { new Common::MemoryDeserializeStream(buffer) }; }, inValue); diff --git a/Engine/Source/RHI/Include/RHI/Instance.h b/Engine/Source/RHI/Include/RHI/Instance.h index 6bbf3e6d2..63b619f9e 100644 --- a/Engine/Source/RHI/Include/RHI/Instance.h +++ b/Engine/Source/RHI/Include/RHI/Instance.h @@ -15,7 +15,8 @@ namespace RHI { RHIType GetPlatformRHIType(); std::string GetPlatformDefaultRHIAbbrString(); - RHIType RHIAbbrStringToRHIType(const std::string& abbrString); + std::string GetAbbrStringByType(RHIType type); + RHIType GetRHITypeByAbbrString(const std::string& abbrString); std::string GetRHIModuleNameByType(RHIType type); class Instance { diff --git a/Engine/Source/RHI/Src/Instance.cpp b/Engine/Source/RHI/Src/Instance.cpp index 6811d9771..264964798 100644 --- a/Engine/Source/RHI/Src/Instance.cpp +++ b/Engine/Source/RHI/Src/Instance.cpp @@ -24,7 +24,17 @@ namespace RHI { #endif } - RHIType RHIAbbrStringToRHIType(const std::string& abbrString) + std::string GetAbbrStringByType(RHIType type) + { + static std::unordered_map map = { + { RHIType::directX12, "dx12" }, + { RHIType::vulkan, "vulkan" }, + { RHIType::dummy, "dummy" } + }; + return map.at(type); + } + + RHIType GetRHITypeByAbbrString(const std::string& abbrString) // NOLINT { static std::unordered_map map = { { "dx12", RHIType::directX12 }, diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 41f28ab80..1d1d719e3 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -7,11 +7,12 @@ #include #include -#include +#include #include #include #include #include +#include namespace Runtime { using Entity = size_t; @@ -23,13 +24,16 @@ namespace Runtime { class ECRegistry; - class EClass() System { + template + concept ECRegistryOrConst = std::is_same_v, ECRegistry>; + + class RUNTIME_API EClass() System { public: EClassBody(System) explicit System(ECRegistry& inRegistry); virtual ~System(); - virtual void Execute(float inDeltaTimeMs); + virtual void Tick(float inDeltaTimeMs); protected: ECRegistry& registry; @@ -41,14 +45,14 @@ namespace Runtime::Internal { using ElemPtr = void*; template const Mirror::Class* GetClass(); - template struct LambdaTraits; + template struct MemberFuncPtrTraits; class CompRtti { public: explicit CompRtti(CompClass inClass); void Bind(size_t inOffset); - Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const; - Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const; + Mirror::Any MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const; + Mirror::Any MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const; void Destruct(ElemPtr inElem) const; Mirror::Any Get(ElemPtr inElem) const; CompClass Class() const; @@ -67,16 +71,16 @@ namespace Runtime::Internal { size_t offset; }; - class Archetype { + class RUNTIME_API Archetype { public: explicit Archetype(const std::vector& inRttiVec); bool Contains(CompClass inClazz) const; bool ContainsAll(const std::vector& inClasses) const; - bool NotContainsAny(const std::vector& inCompClasses) const; + bool NotContainsAny(const std::vector& inClasses) const; ElemPtr EmplaceElem(Entity inEntity); ElemPtr EmplaceElem(Entity inEntity, ElemPtr inSrcElem, const std::vector& inSrcRttiVec); - Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef); + Mirror::Any EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Any& inCompRef); void EraseElem(Entity inEntity); ElemPtr GetElem(Entity inEntity) const; Mirror::Any GetComp(Entity inEntity, CompClass inCompClass); @@ -184,7 +188,7 @@ namespace Runtime { G& globalCompRef; }; - class ScopedUpdaterDyn { + class RUNTIME_API ScopedUpdaterDyn { public: ScopedUpdaterDyn(ECRegistry& inRegistry, CompClass inClass, Entity inEntity, const Mirror::Any& inCompRef); ~ScopedUpdaterDyn(); @@ -198,10 +202,10 @@ namespace Runtime { ECRegistry& registry; CompClass clazz; Entity entity; - const Mirror::Any& compRef; + Mirror::Any compRef; }; - class GScopedUpdaterDyn { + class RUNTIME_API GScopedUpdaterDyn { public: GScopedUpdaterDyn(ECRegistry& inRegistry, GCompClass inClass, const Mirror::Any& inGlobalCompRef); ~GScopedUpdaterDyn(); @@ -214,7 +218,7 @@ namespace Runtime { private: ECRegistry& registry; GCompClass clazz; - const Mirror::Any& globalCompRef; + Mirror::Any globalCompRef; }; template @@ -224,73 +228,82 @@ namespace Runtime { struct Exclude {}; template - class View; + class BasicView; - template - class View, C...> { + template + class BasicView, C...> { public: - explicit View(ECRegistry& inRegistry); - NonCopyable(View) - NonMovable(View) + using ResultVector = std::vector>; + using ConstIter = typename ResultVector::const_iterator; + + explicit BasicView(R& inRegistry); + NonCopyable(BasicView) + NonMovable(BasicView) template void Each(F&& inFunc) const; - auto Begin(); - auto Begin() const; - auto End(); - auto End() const; - auto begin(); - auto begin() const; - auto end(); - auto end() const; + size_t Size() const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; private: - void Evaluate(ECRegistry& inRegistry); + void Evaluate(R& inRegistry); - std::vector> result; + ResultVector result; }; - class RuntimeViewRule { + template using View = BasicView; + template using ConstView = BasicView; + + class RUNTIME_API RuntimeFilter { public: - RuntimeViewRule(); - template RuntimeViewRule& Include(); - template RuntimeViewRule& Exclude(); - RuntimeViewRule& IncludeDyn(CompClass inClass); - RuntimeViewRule& ExcludeDyn(CompClass inClass); + RuntimeFilter(); + template RuntimeFilter& Include(); + template RuntimeFilter& Exclude(); + RuntimeFilter& IncludeDyn(CompClass inClass); + RuntimeFilter& ExcludeDyn(CompClass inClass); private: - friend class RuntimeView; + template friend class BasicRuntimeView; std::unordered_set includes; std::unordered_set excludes; }; - class RuntimeView { + template + class BasicRuntimeView { public: - explicit RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); - NonCopyable(RuntimeView) - NonMovable(RuntimeView) + using ResultEntitiesVector = std::vector; + using ConstIter = typename ResultEntitiesVector::const_iterator; + + explicit BasicRuntimeView(R& inRegistry, const RuntimeFilter& inFilter); + NonCopyable(BasicRuntimeView) + NonMovable(BasicRuntimeView) template void Each(F&& inFunc) const; - auto Begin(); - auto Begin() const; - auto End(); - auto End() const; - auto begin(); - auto begin() const; - auto end(); - auto end() const; + size_t Size() const; + ConstIter Begin() const; + ConstIter End() const; + ConstIter begin() const; + ConstIter end() const; private: - template void InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const; - template decltype(auto) GetCompRef(std::vector& inComps) const; - void Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs); + using ResultVector = std::vector>>; + + template void InvokeTraverseFuncInternal(F&& inFunc, const std::pair>& inEntityAndComps, std::index_sequence) const; + template decltype(auto) GetCompRef(const std::vector& inComps) const; + void Evaluate(R& inRegistry, const RuntimeFilter& inFilter); std::unordered_map slotMap; - std::vector resultEntities; - std::vector>> result; + ResultEntitiesVector resultEntities; + ResultVector result; }; - class Observer { + using RuntimeView = BasicRuntimeView; + using ConstRuntimeView = BasicRuntimeView; + + class RUNTIME_API Observer { public: using ConstIter = std::vector::const_iterator; using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; @@ -301,33 +314,35 @@ namespace Runtime { NonCopyable(Observer) NonMovable(Observer) - template void ObConstructed(); - template void ObUpdated(); - template void ObRemove(); + template Observer& ObConstructed(); + template Observer& ObUpdated(); + Observer& ObConstructedDyn(CompClass inClass); + Observer& ObUpdatedDyn(CompClass inClass); + size_t Size() const; void Each(const EntityTraverseFunc& inFunc) const; void Clear(); - void Reset(); + void UnbindAll(); ConstIter Begin() const; ConstIter End() const; ConstIter begin() const; ConstIter end() const; private: - void OnEvent(Common::Event& inEvent); + Observer& OnEvent(Common::Delegate& inEvent); void RecordEntity(ECRegistry& inRegistry, Entity inEntity); ECRegistry& registry; - std::vector> receiverHandles; + std::vector> receiverHandles; std::vector entities; }; - class MIRROR_API ECRegistry { + class RUNTIME_API ECRegistry { public: using EntityTraverseFunc = Internal::EntityPool::EntityTraverseFunc; using DynUpdateFunc = std::function; using ConstIter = Internal::EntityPool::ConstIter; - using CompEvent = Common::Event; - using GCompEvent = Common::Event; + using CompEvent = Common::Delegate; + using GCompEvent = Common::Delegate; struct CompEvents { CompEvent onConstructed; @@ -374,7 +389,9 @@ namespace Runtime { template const C* Find(Entity inEntity) const; template C& Get(Entity inEntity); template const C& Get(Entity inEntity) const; - template View, C...> View(Exclude); + template Runtime::View, C...> View(Exclude = {}); + template Runtime::ConstView, C...> View(Exclude = {}) const; + template Runtime::ConstView, C...> ConstView(Exclude = {}) const; template CompEvents& Events(); Observer Observer(); @@ -390,7 +407,9 @@ namespace Runtime { Mirror::Any GetDyn(CompClass inClass, Entity inEntity); Mirror::Any GetDyn(CompClass inClass, Entity inEntity) const; CompEvents& EventsDyn(CompClass inClass); - RuntimeView RuntimeView(const RuntimeViewRule& inRule); + Runtime::RuntimeView RuntimeView(const RuntimeFilter& inFilter); + Runtime::ConstRuntimeView RuntimeView(const RuntimeFilter& inFilter) const; + Runtime::ConstRuntimeView ConstRuntimeView(const RuntimeFilter& inFilter) const; // global component static template G& GEmplace(Args&&... inArgs); @@ -419,8 +438,8 @@ namespace Runtime { GCompEvents& GEventsDyn(GCompClass inClass); private: - template friend class View; - friend class RuntimeView; + template friend class BasicView; + template friend class BasicRuntimeView; template void NotifyConstructed(Entity inEntity); template void NotifyRemove(Entity inEntity); @@ -439,7 +458,7 @@ namespace Runtime { std::unordered_map globalCompEvents; }; - class SystemGroup { + class RUNTIME_API SystemGroup { public: explicit SystemGroup(std::string inName); @@ -457,7 +476,7 @@ namespace Runtime { std::unordered_map systems; }; - class SystemGraph { + class RUNTIME_API SystemGraph { public: SystemGraph(); @@ -514,10 +533,18 @@ namespace Runtime::Internal { return &Mirror::Class::Get(); } - template - struct LambdaTraits> { - static constexpr auto ArgSize = sizeof...(T); - using ArgsTupleType = std::tuple; + template + struct MemberFuncPtrTraits { + static constexpr auto ArgSize = sizeof...(Args); + using ClassType = Class; + using ArgsTupleType = std::tuple; + }; + + template + struct MemberFuncPtrTraits { + static constexpr auto ArgSize = sizeof...(Args); + using ClassType = const Class; + using ArgsTupleType = std::tuple; }; inline auto Archetype::All() const @@ -578,82 +605,68 @@ namespace Runtime { return globalCompRef.As(); } - template - View, C...>::View(ECRegistry& inRegistry) + template + BasicView, C...>::BasicView(R& inRegistry) { Evaluate(inRegistry); } - template + template template - void View, C...>::Each(F&& inFunc) const + void BasicView, C...>::Each(F&& inFunc) const { - for (const auto& entity : result) { - std::apply(inFunc, entity); + for (const auto& entityAndComps : result) { + if constexpr (Internal::MemberFuncPtrTraits::ArgSize == 1) { + inFunc(std::get<0>(entityAndComps)); + } else { + std::apply(inFunc, entityAndComps); + } } } - template - auto View, C...>::Begin() + template + size_t BasicView, C...>::Size() const { - return result.begin(); + return result.size(); } - template - auto View, C...>::Begin() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::Begin() const { return result.begin(); } - template - auto View, C...>::End() + template + typename BasicView, C...>::ConstIter BasicView, C...>::End() const { return result.end(); } - template - auto View, C...>::End() const - { - return result.end(); - } - - template - auto View, C...>::begin() - { - return Begin(); - } - - template - auto View, C...>::begin() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::begin() const { return Begin(); } - template - auto View, C...>::end() - { - return End(); - } - - template - auto View, C...>::end() const + template + typename BasicView, C...>::ConstIter BasicView, C...>::end() const { return End(); } - template - void View, C...>::Evaluate(ECRegistry& inRegistry) + template + void BasicView, C...>::Evaluate(R& inRegistry) { std::vector includeCompIds; includeCompIds.reserve(sizeof...(C)); (void) std::initializer_list { ([&]() -> void { - includeCompIds.emplace_back(Internal::GetClass()); + includeCompIds.emplace_back(Internal::GetClass>()); }(), 0)... }; std::vector excludeCompIds; excludeCompIds.reserve(sizeof...(E)); (void) std::initializer_list { ([&]() -> void { - excludeCompIds.emplace_back(Internal::GetClass()); + excludeCompIds.emplace_back(Internal::GetClass()); }(), 0)... }; for (auto& archetype : inRegistry.archetypes | std::views::values) { @@ -663,35 +676,107 @@ namespace Runtime { result.reserve(result.size() + archetype.Size()); for (auto entity : archetype.All()) { - result.emplace_back(entity, inRegistry.Get(entity)...); + result.emplace_back(entity, inRegistry.template Get>(entity)...); } } } + template + BasicRuntimeView::BasicRuntimeView(R& inRegistry, const RuntimeFilter& inFilter) + { + Evaluate(inRegistry, inFilter); + } + + template template - void RuntimeView::Each(F&& inFunc) const + void BasicRuntimeView::Each(F&& inFunc) const { + using Traits = Internal::MemberFuncPtrTraits; + for (const auto& pair : result) { - InvokeTraverseFuncInternal::ArgsTupleType>(std::forward(inFunc), pair, std::make_index_sequence::ArgSize> {}); + InvokeTraverseFuncInternal(std::forward(inFunc), pair, std::make_index_sequence {}); } } + template + size_t BasicRuntimeView::Size() const + { + return resultEntities.size(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::Begin() const + { + return resultEntities.begin(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::End() const + { + return resultEntities.end(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::begin() const + { + return Begin(); + } + + template + typename BasicRuntimeView::ConstIter BasicRuntimeView::end() const + { + return End(); + } + + template template - void RuntimeView::InvokeTraverseFuncInternal(F&& inFunc, std::pair>& inEntityAndComps, std::index_sequence) const + void BasicRuntimeView::InvokeTraverseFuncInternal(F&& inFunc, const std::pair>& inEntityAndComps, std::index_sequence) const { - inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); + inFunc(inEntityAndComps.first, GetCompRef>(inEntityAndComps.second)...); } + template template - decltype(auto) RuntimeView::GetCompRef(std::vector& inComps) const + decltype(auto) BasicRuntimeView::GetCompRef(const std::vector& inComps) const { static_assert(std::is_reference_v); - const auto compIndex = slotMap.at(Internal::GetClass()); + const auto compIndex = slotMap.at(Internal::GetClass>()); return inComps[compIndex].template As(); } + template + void BasicRuntimeView::Evaluate(R& inRegistry, const RuntimeFilter& inFilter) + { + const std::vector includes(inFilter.includes.begin(), inFilter.includes.end()); + const std::vector excludes(inFilter.excludes.begin(), inFilter.excludes.end()); + + slotMap.reserve(includes.size()); + for (auto i = 0; i < includes.size(); i++) { + slotMap.emplace(includes[i], i); + } + + for (auto& archetype : inRegistry.archetypes | std::views::values) { + if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { + continue; + } + + resultEntities.reserve(result.size() + archetype.Size()); + result.reserve(result.size() + archetype.Size()); + for (const auto entity : archetype.All()) { + std::vector comps; + comps.reserve(includes.size()); + for (const auto clazz : includes) { + comps.emplace_back(archetype.GetComp(entity, clazz)); + } + + resultEntities.emplace_back(entity); + result.emplace_back(entity, std::move(comps)); + } + } + } + template - RuntimeViewRule& RuntimeViewRule::Include() + RuntimeFilter& RuntimeFilter::Include() { const auto* clazz = Internal::GetClass(); Assert(!includes.contains(clazz)); @@ -700,7 +785,7 @@ namespace Runtime { } template - RuntimeViewRule& RuntimeViewRule::Exclude() + RuntimeFilter& RuntimeFilter::Exclude() { const auto* clazz = Internal::GetClass(); Assert(!excludes.contains(clazz)); @@ -709,21 +794,15 @@ namespace Runtime { } template - void Observer::ObConstructed() - { - OnEvent(registry.Events().onConstructed); - } - - template - void Observer::ObUpdated() + Observer& Observer::ObConstructed() { - OnEvent(registry.Events().onUpdated); + return OnEvent(registry.Events().onConstructed); } template - void Observer::ObRemove() + Observer& Observer::ObUpdated() { - OnEvent(registry.Events().onRemove); + return OnEvent(registry.Events().onUpdated); } template @@ -741,13 +820,15 @@ namespace Runtime { template void ECRegistry::Update(Entity inEntity, F&& inFunc) { - UpdateDyn(Internal::GetClass(), inEntity, std::forward(inFunc)); + UpdateDyn(Internal::GetClass(), inEntity, [&](const Mirror::Any& ref) -> void { + inFunc(ref.As()); + }); } template ScopedUpdater ECRegistry::Update(Entity inEntity) { - Assert(Valid(inEntity) && Has()); + Assert(Valid(inEntity) && Has(inEntity)); return { *this, inEntity, Get(inEntity) }; } @@ -782,9 +863,21 @@ namespace Runtime { } template - View, C...> ECRegistry::View(Exclude) + Runtime::View, C...> ECRegistry::View(Exclude) + { + return Runtime::View, C...>(*this); + } + + template + Runtime::ConstView, C...> ECRegistry::View(Exclude) const + { + return Runtime::ConstView, C...>(*this); + } + + template + Runtime::ConstView, C...> ECRegistry::ConstView(Exclude) const { - return { *this }; + return Runtime::ConstView, C...>(*this); } template @@ -814,7 +907,7 @@ namespace Runtime { template G& ECRegistry::GEmplace(Args&&... inArgs) { - return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)); + return GEmplaceDyn(Internal::GetClass(), Mirror::ForwardAsArgList(std::forward(inArgs)...)).template As(); } template @@ -826,7 +919,9 @@ namespace Runtime { template void ECRegistry::GUpdate(F&& inFunc) { - GUpdateDyn(Internal::GetClass(), std::forward(inFunc)); + GUpdateDyn(Internal::GetClass(), [&](const Mirror::Any& ref) -> void { + inFunc(ref.As()); + }); } template diff --git a/Engine/Source/Runtime/Include/Runtime/Engine.h b/Engine/Source/Runtime/Include/Runtime/Engine.h index a0fae201a..c72380abf 100644 --- a/Engine/Source/Runtime/Include/Runtime/Engine.h +++ b/Engine/Source/Runtime/Include/Runtime/Engine.h @@ -27,7 +27,7 @@ namespace Runtime { void MountWorld(World* inWorld); void UnmountWorld(World* inWorld); Render::RenderModule& GetRenderModule() const; - void Tick(float inTimeMs) const; + void Tick(float inTimeSeconds) const; Common::UniqueRef CreateWorld(const std::string& inName = "") const; protected: @@ -45,7 +45,7 @@ namespace Runtime { bool IsEditor() override; }; - struct RUNTIME_API IGameModule : Core::Module { // NOLINT + struct RUNTIME_API IEngineModule : Core::Module { // NOLINT virtual Engine* CreateEngine(const EngineInitParams& inParams) = 0; }; @@ -56,6 +56,6 @@ namespace Runtime { static Engine& Get(); private: - static Engine* engine; + static Common::UniqueRef engine; }; } diff --git a/Engine/Source/Runtime/Include/Runtime/World.h b/Engine/Source/Runtime/Include/Runtime/World.h index 976ae53df..5194d1ad5 100644 --- a/Engine/Source/Runtime/Include/Runtime/World.h +++ b/Engine/Source/Runtime/Include/Runtime/World.h @@ -18,17 +18,12 @@ namespace Runtime { max }; - class World { + class RUNTIME_API World { public: NonCopyable(World) NonMovable(World) ~World(); - private: - friend class Engine; - - explicit World(const std::string& inName = ""); - void SetSystemGraph(const SystemGraph& inSystemGraph); void Reset(); PlayStatus PlayStatus() const; @@ -39,6 +34,11 @@ namespace Runtime { void Resume(); void Pause(); void Stop(); + + private: + friend class Engine; + + explicit World(const std::string& inName = ""); void Tick(float inTimeMs); std::string name; diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index 05a875f22..c81cb0b8d 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -14,7 +14,7 @@ namespace Runtime { System::~System() = default; - void System::Execute(float inDeltaTimeMs) {} + void System::Tick(float inDeltaTimeMs) {} } namespace Runtime::Internal { @@ -31,13 +31,13 @@ namespace Runtime::Internal { offset = inOffset; } - Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveConstruct(ElemPtr inElem, const Mirror::Any& inOther) const { auto* compBegin = static_cast(inElem) + offset; return clazz->InplaceNewDyn(compBegin, { inOther }); } - Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Argument& inOther) const + Mirror::Any CompRtti::MoveAssign(ElemPtr inElem, const Mirror::Any& inOther) const { auto* compBegin = static_cast(inElem) + offset; auto compRef = clazz->InplaceGetObject(compBegin); @@ -102,18 +102,18 @@ namespace Runtime::Internal { bool Archetype::ContainsAll(const std::vector& inClasses) const { - for (const auto& rtti : rttiVec) { - if (!Contains(rtti.Class())) { + for (const auto& clazz : inClasses) { + if (!Contains(clazz)) { return false; } } return true; } - bool Archetype::NotContainsAny(const std::vector& inCompClasses) const + bool Archetype::NotContainsAny(const std::vector& inClasses) const { - for (const auto& rtti : rttiVec) { - if (Contains(rtti.Class())) { + for (const auto& clazz : inClasses) { + if (Contains(clazz)) { return false; } } @@ -142,7 +142,7 @@ namespace Runtime::Internal { return newElem; } - Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Argument& inCompRef) // NOLINT + Mirror::Any Archetype::EmplaceComp(Entity inEntity, CompClass inCompClass, const Mirror::Any& inCompRef) // NOLINT { ElemPtr elem = ElemAt(entityMap.at(inEntity)); return GetCompRtti(inCompClass).MoveConstruct(elem, inCompRef); @@ -162,6 +162,7 @@ namespace Runtime::Internal { entityMap.erase(inEntity); elemMap.at(elemIndex) = entityToLastElem; elemMap.erase(lastElemIndex); + size--; } ElemPtr Archetype::GetElem(Entity inEntity) const @@ -403,103 +404,43 @@ namespace Runtime { registry.GNotifyUpdatedDyn(clazz); } - RuntimeViewRule::RuntimeViewRule() = default; + RuntimeFilter::RuntimeFilter() = default; - RuntimeViewRule& RuntimeViewRule::IncludeDyn(CompClass inClass) + RuntimeFilter& RuntimeFilter::IncludeDyn(CompClass inClass) { includes.emplace(inClass); return *this; } - RuntimeViewRule& RuntimeViewRule::ExcludeDyn(CompClass inClass) + RuntimeFilter& RuntimeFilter::ExcludeDyn(CompClass inClass) { excludes.emplace(inClass); return *this; } - RuntimeView::RuntimeView(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) - { - Evaluate(inRegistry, inArgs); - } - - auto RuntimeView::Begin() - { - return resultEntities.begin(); - } - - auto RuntimeView::Begin() const - { - return resultEntities.begin(); - } - - auto RuntimeView::End() - { - return resultEntities.end(); - } - - auto RuntimeView::End() const - { - return resultEntities.end(); - } - - auto RuntimeView::begin() - { - return Begin(); - } - - auto RuntimeView::begin() const + Observer::Observer(ECRegistry& inRegistry) + : registry(inRegistry) { - return Begin(); } - auto RuntimeView::end() - { - return End(); - } - - auto RuntimeView::end() const + Observer::~Observer() { - return End(); + UnbindAll(); } - void RuntimeView::Evaluate(ECRegistry& inRegistry, const RuntimeViewRule& inArgs) + Observer& Observer::ObConstructedDyn(CompClass inClass) { - const std::vector includes(inArgs.includes.begin(), inArgs.includes.end()); - const std::vector excludes(inArgs.excludes.begin(), inArgs.excludes.end()); - - slotMap.reserve(includes.size()); - for (auto i = 0; i < includes.size(); i++) { - slotMap.emplace(includes[i], i); - } - - for (auto& [_, archetype] : inRegistry.archetypes) { - if (!archetype.ContainsAll(includes) || !archetype.NotContainsAny(excludes)) { - continue; - } - - resultEntities.reserve(result.size() + archetype.Size()); - result.reserve(result.size() + archetype.Size()); - for (const auto entity : archetype.All()) { - std::vector comps; - comps.reserve(includes.size()); - for (const auto clazz : includes) { - comps.emplace_back(archetype.GetComp(entity, clazz)); - } - - resultEntities.emplace_back(entity); - result.emplace_back(entity, std::move(comps)); - } - } + return OnEvent(registry.EventsDyn(inClass).onConstructed); } - Observer::Observer(ECRegistry& inRegistry) - : registry(inRegistry) + Observer& Observer::ObUpdatedDyn(CompClass inClass) { + return OnEvent(registry.EventsDyn(inClass).onUpdated); } - Observer::~Observer() + size_t Observer::Size() const { - Reset(); + return entities.size(); } void Observer::Each(const EntityTraverseFunc& inFunc) const @@ -514,9 +455,9 @@ namespace Runtime { entities.clear(); } - void Observer::Reset() + void Observer::UnbindAll() { - for (auto& [handle, deleter] : receiverHandles) { + for (auto& deleter : receiverHandles | std::views::values) { deleter(); } receiverHandles.clear(); @@ -547,14 +488,15 @@ namespace Runtime { entities.emplace_back(inEntity); } - void Observer::OnEvent(Common::Event& inEvent) + Observer& Observer::OnEvent(Common::Delegate& inEvent) { const auto handle = inEvent.BindMember<&Observer::RecordEntity>(*this); receiverHandles.emplace_back( handle, - [&]() -> void { + [&inEvent, handle]() -> void { inEvent.Unbind(handle); }); + return *this; } ECRegistry::ECRegistry() @@ -660,9 +602,19 @@ namespace Runtime { return End(); } - RuntimeView ECRegistry::RuntimeView(const RuntimeViewRule& inRule) + Runtime::RuntimeView ECRegistry::RuntimeView(const RuntimeFilter& inFilter) { - return Runtime::RuntimeView { *this, inRule }; + return Runtime::RuntimeView { *this, inFilter }; + } + + Runtime::ConstRuntimeView ECRegistry::RuntimeView(const RuntimeFilter& inFilter) const + { + return Runtime::ConstRuntimeView { *this, inFilter }; + } + + Runtime::ConstRuntimeView ECRegistry::ConstRuntimeView(const RuntimeFilter& inFilter) const + { + return Runtime::ConstRuntimeView { *this, inFilter }; } void ECRegistry::NotifyUpdatedDyn(CompClass inClass, Entity inEntity) @@ -706,19 +658,15 @@ namespace Runtime { const Internal::ArchetypeId newArchetypeId = archetypeId + inClass->GetTypeInfo()->id; entities.SetArchetype(inEntity, newArchetypeId); - Internal::Archetype* newArchetype; - if (archetypes.contains(newArchetypeId)) { - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); - archetype.EraseElem(inEntity); - } else { + if (!archetypes.contains(newArchetypeId)) { archetypes.emplace(newArchetypeId, Internal::Archetype(archetype.NewRttiVecByAdd(Internal::CompRtti(inClass)))); - newArchetype = &archetypes.at(newArchetypeId); - newArchetype->EmplaceElem(inEntity); } + Internal::Archetype& newArchetype = archetypes.at(newArchetypeId); + newArchetype.EmplaceElem(inEntity, archetype.GetElem(inEntity), archetype.GetRttiVec()); + archetype.EraseElem(inEntity); Mirror::Any tempObj = inClass->ConstructDyn(inArgs); - Mirror::Any compRef = newArchetype->EmplaceComp(inEntity, inClass, tempObj.Ref()); + Mirror::Any compRef = newArchetype.EmplaceComp(inEntity, inClass, tempObj.Ref()); NotifyConstructedDyn(inClass, inEntity); return compRef; } @@ -868,7 +816,7 @@ namespace Runtime { Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) { Assert(GHasDyn(inClass)); - return globalComps.at(inClass); + return globalComps.at(inClass).Ref(); } Mirror::Any ECRegistry::GGetDyn(GCompClass inClass) const @@ -1046,7 +994,7 @@ namespace Runtime { void SystemGraphExecutor::Tick(float inDeltaTimeMs) { pipeline.ParallelPerformAction([&](const SystemPipeline::SystemContext& context) -> void { - context.instance->Execute(inDeltaTimeMs); + context.instance->Tick(inDeltaTimeMs); }); } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/Engine.cpp b/Engine/Source/Runtime/Src/Engine.cpp index c0a077ee2..1526c1141 100644 --- a/Engine/Source/Runtime/Src/Engine.cpp +++ b/Engine/Source/Runtime/Src/Engine.cpp @@ -19,7 +19,7 @@ namespace Runtime { Assert(renderModule != nullptr); Render::RenderModuleInitParams initParams; - initParams.rhiType = RHI::RHIAbbrStringToRHIType(inParams.rhiType); + initParams.rhiType = RHI::GetRHITypeByAbbrString(inParams.rhiType); renderModule->Initialize(initParams); } @@ -44,13 +44,13 @@ namespace Runtime { return *renderModule; } - void Engine::Tick(float inTimeMs) const + void Engine::Tick(float inTimeSeconds) const { for (auto* world : worlds) { if (!world->Playing()) { continue; } - world->Tick(inTimeMs); + world->Tick(inTimeSeconds); } } @@ -59,7 +59,7 @@ namespace Runtime { return new World(inName); } - Engine* EngineHolder::engine = nullptr; + Common::UniqueRef EngineHolder::engine = nullptr; MinEngine::MinEngine(const EngineInitParams& inParams) : Engine(inParams) @@ -76,7 +76,7 @@ namespace Runtime { void EngineHolder::Load(const std::string& inModuleName, const EngineInitParams& inInitParams) { Assert(engine == nullptr); - auto& gameModule = Core::ModuleManager::Get().GetOrLoadTyped(inModuleName); + auto& gameModule = Core::ModuleManager::Get().GetOrLoadTyped(inModuleName); engine = gameModule.CreateEngine(inInitParams); } diff --git a/Engine/Source/Runtime/Src/World.cpp b/Engine/Source/Runtime/Src/World.cpp index 3c4b0af28..7db9ed507 100644 --- a/Engine/Source/Runtime/Src/World.cpp +++ b/Engine/Source/Runtime/Src/World.cpp @@ -8,6 +8,7 @@ namespace Runtime { World::World(const std::string& inName) : name(inName) + , playStatus(PlayStatus::stopped) { EngineHolder::Get().MountWorld(this); } diff --git a/Engine/Source/Runtime/Test/ECSTest.cpp b/Engine/Source/Runtime/Test/ECSTest.cpp index 43537705c..26cdd767a 100644 --- a/Engine/Source/Runtime/Test/ECSTest.cpp +++ b/Engine/Source/Runtime/Test/ECSTest.cpp @@ -3,6 +3,7 @@ // #include +#include TEST(ECSTest, EntityTest) { @@ -46,12 +47,357 @@ TEST(ECSTest, ComponentStaticTest) ASSERT_EQ(registry.Get(entity1).value, 2); const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.Has(entity0)); ASSERT_EQ(constRegistry.Find(entity0)->value, 1); ASSERT_EQ(constRegistry.Find(entity1)->value, 2); ASSERT_EQ(constRegistry.Get(entity0).value, 1); ASSERT_EQ(constRegistry.Get(entity1).value, 2); - // TODO + registry.Remove(entity0); + ASSERT_FALSE(constRegistry.Has(entity0)); + + const auto entity2 = registry.Create(); + registry.Emplace(entity2, 3); + registry.Emplace(entity2, 4.0f); + ASSERT_TRUE(constRegistry.Has(entity2)); + ASSERT_TRUE(constRegistry.Has(entity2)); + ASSERT_EQ(constRegistry.Get(entity2).value, 3); + ASSERT_EQ(constRegistry.Get(entity2).value, 4.0f); + + const auto entity3 = registry.Create(); + registry.Emplace(entity3, 5); + registry.Emplace(entity3, 6.0f); + registry.Remove(entity3); + ASSERT_FALSE(constRegistry.Has(entity3)); + ASSERT_TRUE(constRegistry.Has(entity3)); + ASSERT_EQ(constRegistry.Get(entity3).value, 6.0f); + + std::unordered_set expected = { entity1, entity2 }; + const auto view0 = registry.View(); + ASSERT_EQ(view0.Size(), 2); + view0.Each([&](Entity e, CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + expected = { entity1 }; + const auto view1 = registry.ConstView(Exclude {}); + ASSERT_EQ(view1.Size(), 1); + view1.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + expected = { entity2, entity3 }; + const auto view2 = registry.View(); + ASSERT_EQ(view2.Size(), 2); + for (const auto& [entity, compB] : view2) { + ASSERT_TRUE(expected.contains(entity)); + } + + expected = { entity3 }; + const auto view3 = registry.ConstView(Exclude {}); + ASSERT_EQ(view3.Size(), 1); + for (const auto& [entity, compB] : view3) { + ASSERT_TRUE(expected.contains(entity)); + } +} + +TEST(ECSTest, ComponentDynamicTest) +{ + CompClass compAClass = &Mirror::Class::Get(); + CompClass compBClass = &Mirror::Class::Get(); + + ECRegistry registry; + const ECRegistry& constRegistry = registry; + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.EmplaceDyn(compAClass, entity0, Mirror::ForwardAsArgList(1)); + registry.EmplaceDyn(compAClass, entity1, Mirror::ForwardAsArgList(2)); + ASSERT_TRUE(registry.HasDyn(compAClass, entity0)); + ASSERT_TRUE(constRegistry.HasDyn(compAClass, entity1)); + ASSERT_EQ(registry.GetDyn(compAClass, entity0).As().value, 1); + ASSERT_EQ(constRegistry.GetDyn(compAClass, entity1).As().value, 2); + ASSERT_EQ(registry.FindDyn(compAClass, entity0).As().value, 1); + ASSERT_EQ(constRegistry.FindDyn(compAClass, entity1).As().value, 2); + + std::unordered_set expected = { entity0, entity1 }; + const auto view0 = registry.ConstRuntimeView( + RuntimeFilter() + .IncludeDyn(compAClass)); + ASSERT_EQ(view0.Size(), 2); + view0.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto entity2 = registry.Create(); + registry.EmplaceDyn(compAClass, entity2, Mirror::ForwardAsArgList(3)); + registry.EmplaceDyn(compBClass, entity2, Mirror::ForwardAsArgList(4.0f)); + const auto entity3 = registry.Create(); + registry.EmplaceDyn(compBClass, entity3, Mirror::ForwardAsArgList(5.0f)); + + const auto view1 = registry.RuntimeView( + RuntimeFilter() + .Include()); + expected = { entity0, entity1, entity2 }; + ASSERT_EQ(view1.Size(), 3); + for (const auto& entity : view1) { + ASSERT_TRUE(expected.contains(entity)); + } + + const auto view2 = registry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Exclude()); + expected = { entity0, entity1 }; + ASSERT_EQ(view2.Size(), 2); + view2.Each([&](Entity e, const CompA& compA) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view3 = registry.RuntimeView( + RuntimeFilter() + .Include()); + expected = { entity2, entity3 }; + ASSERT_EQ(view3.Size(), 2); + view3.Each([&](Entity e, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view4 = registry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Exclude()); + expected = { entity3 }; + ASSERT_EQ(view4.Size(), 1); + view4.Each([&](Entity e, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto view5 = constRegistry.ConstRuntimeView( + RuntimeFilter() + .Include() + .Include()); + expected = { entity2 }; + ASSERT_EQ(view5.Size(), 1); + view5.Each([&](Entity e, const CompA& compA, const CompB& compB) -> void { + ASSERT_TRUE(expected.contains(e)); + }); +} + +TEST(ECSTest, GlobalComponentStaticTest) +{ + ECRegistry registry; + registry.GEmplace(1); + ASSERT_TRUE(registry.GHas()); + ASSERT_EQ(registry.GFind()->value, 1); + ASSERT_EQ(registry.GGet().value, 1); + + const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.GHas()); + ASSERT_EQ(constRegistry.GFind()->value, 1); + ASSERT_EQ(constRegistry.GGet().value, 1); + + registry.GEmplace(2.0f); + ASSERT_TRUE(registry.GHas()); + ASSERT_TRUE(registry.GHas()); + ASSERT_EQ(registry.GGet().value, 2.0f); + + registry.GRemove(); + ASSERT_TRUE(registry.GHas()); + ASSERT_FALSE(registry.GHas()); +} + +TEST(ECSTest, GlobalComponentDynamicTest) +{ + GCompClass gCompAClass = &Mirror::Class::Get(); + GCompClass gCompBClass = &Mirror::Class::Get(); + + ECRegistry registry; + registry.GEmplaceDyn(gCompAClass, Mirror::ForwardAsArgList(1)); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_EQ(registry.GFindDyn(gCompAClass).As().value, 1); + ASSERT_EQ(registry.GGetDyn(gCompAClass).As().value, 1); + + const ECRegistry& constRegistry = registry; + ASSERT_TRUE(constRegistry.GHasDyn(gCompAClass)); + ASSERT_EQ(constRegistry.GFindDyn(gCompAClass).As().value, 1); + ASSERT_EQ(constRegistry.GGetDyn(gCompAClass).As().value, 1); + + registry.GEmplaceDyn(gCompBClass, Mirror::ForwardAsArgList(2.0f)); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_TRUE(registry.GHasDyn(gCompBClass)); + ASSERT_EQ(registry.GGetDyn(gCompBClass).As().value, 2.0f); + + registry.GRemoveDyn(gCompBClass); + ASSERT_TRUE(registry.GHasDyn(gCompAClass)); + ASSERT_FALSE(registry.GHasDyn(gCompBClass)); +} + +TEST(ECSTest, ComponentEventStaticTest) +{ + EventCounts count; + ECRegistry registry; + registry.Events().onConstructed.BindLambda([&](ECRegistry&, Entity) -> void { count.onConstructed++; }); + registry.Events().onUpdated.BindLambda([&](ECRegistry&, Entity) -> void { count.onUpdated++; }); + registry.Events().onRemove.BindLambda([&](ECRegistry&, Entity) -> void { count.onRemove++; }); + + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.Emplace(entity0, 1); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + registry.Emplace(entity1, 2); + ASSERT_EQ(count, EventCounts(2, 0, 0)); + + { + const auto updater = registry.Update(entity0); + updater->value = 3; + } + ASSERT_EQ(count, EventCounts(2, 1, 0)); + registry.Update(entity0, [](CompA& compA) -> void { + compA.value = 4; + }); + ASSERT_EQ(count, EventCounts(2, 2, 0)); + registry.Get(entity1).value = 5; + registry.NotifyUpdated(entity1); + ASSERT_EQ(count, EventCounts(2, 3, 0)); + + registry.Remove(entity0); + ASSERT_EQ(count, EventCounts(2, 3, 1)); + registry.Remove(entity1); + ASSERT_EQ(count, EventCounts(2, 3, 2)); +} + +TEST(ECSTest, ComponentEventDynamicTest) +{ + CompClass compAClass = &Mirror::Class::Get(); + EventCounts count; + ECRegistry registry; + registry.EventsDyn(compAClass).onConstructed.BindLambda([&](ECRegistry&, Entity) -> void { count.onConstructed++; }); + registry.EventsDyn(compAClass).onUpdated.BindLambda([&](ECRegistry&, Entity) -> void { count.onUpdated++; }); + registry.EventsDyn(compAClass).onRemove.BindLambda([&](ECRegistry&, Entity) -> void { count.onRemove++; }); + + const auto entity0 = registry.Create(); + const auto entity1 = registry.Create(); + registry.EmplaceDyn(compAClass, entity0, Mirror::ForwardAsArgList(1)); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + registry.EmplaceDyn(compAClass, entity1, Mirror::ForwardAsArgList(2)); + ASSERT_EQ(count, EventCounts(2, 0, 0)); + + { + const auto updater = registry.UpdateDyn(compAClass, entity0); + updater.As().value = 3; + } + ASSERT_EQ(count, EventCounts(2, 1, 0)); + registry.UpdateDyn(compAClass, entity0, [](const Mirror::Any& ref) -> void { + ref.As().value = 4; + }); + ASSERT_EQ(count, EventCounts(2, 2, 0)); + registry.GetDyn(compAClass, entity1).As().value = 5; + registry.NotifyUpdatedDyn(compAClass, entity1); + ASSERT_EQ(count, EventCounts(2, 3, 0)); + + registry.RemoveDyn(compAClass, entity0); + ASSERT_EQ(count, EventCounts(2, 3, 1)); + registry.RemoveDyn(compAClass, entity1); + ASSERT_EQ(count, EventCounts(2, 3, 2)); } -// TODO +TEST(ECSTest, GlobalComponentEventStaticTest) +{ + EventCounts count; + ECRegistry registry; + registry.GEvents().onConstructed.BindLambda([&](ECRegistry&) -> void { count.onConstructed++; }); + registry.GEvents().onUpdated.BindLambda([&](ECRegistry&) -> void { count.onUpdated++; }); + registry.GEvents().onRemove.BindLambda([&](ECRegistry&) -> void { count.onRemove++; }); + + registry.GEmplace(1); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + + { + const auto updater = registry.GUpdate(); + updater->value = 3; + } + ASSERT_EQ(count, EventCounts(1, 1, 0)); + registry.GUpdate([](GCompA& gCompA) -> void { + gCompA.value = 4; + }); + ASSERT_EQ(count, EventCounts(1, 2, 0)); + registry.GGet().value = 5; + registry.GNotifyUpdated(); + ASSERT_EQ(count, EventCounts(1, 3, 0)); + + registry.GRemove(); + ASSERT_EQ(count, EventCounts(1, 3, 1)); +} + +TEST(ECSTest, GlobalComponentEventDynamicTest) +{ + GCompClass gCompAClass = &Mirror::Class::Get(); + EventCounts count; + ECRegistry registry; + registry.GEventsDyn(gCompAClass).onConstructed.BindLambda([&](ECRegistry&) -> void { count.onConstructed++; }); + registry.GEventsDyn(gCompAClass).onUpdated.BindLambda([&](ECRegistry&) -> void { count.onUpdated++; }); + registry.GEventsDyn(gCompAClass).onRemove.BindLambda([&](ECRegistry&) -> void { count.onRemove++; }); + + registry.GEmplaceDyn(gCompAClass, Mirror::ForwardAsArgList(1)); + ASSERT_EQ(count, EventCounts(1, 0, 0)); + + { + const auto updater = registry.GUpdateDyn(gCompAClass); + updater.As().value = 3; + } + ASSERT_EQ(count, EventCounts(1, 1, 0)); + registry.GUpdateDyn(gCompAClass, [](const Mirror::Any& ref) -> void { + ref.As().value = 4; + }); + ASSERT_EQ(count, EventCounts(1, 2, 0)); + registry.GGetDyn(gCompAClass).As().value = 5; + registry.GNotifyUpdatedDyn(gCompAClass); + ASSERT_EQ(count, EventCounts(1, 3, 0)); + + registry.GRemove(); + ASSERT_EQ(count, EventCounts(1, 3, 1)); +} + +TEST(ECSTest, ObserverTest) +{ + ECRegistry registry; + auto observer = registry.Observer(); + observer + .ObConstructed() + .ObUpdatedDyn(&Mirror::Class::Get()); + + const auto entity0 = registry.Create(); + ASSERT_EQ(observer.Size(), 0); + + registry.Emplace(entity0, 1); + ASSERT_EQ(observer.Size(), 1); + std::unordered_set expected = { entity0 }; + observer.Each([&](Entity e) -> void { + ASSERT_TRUE(expected.contains(e)); + }); + + const auto entity1 = registry.Create(); + registry.Emplace(entity1, 2.0f); + ASSERT_EQ(observer.Size(), 1); + registry.Update(entity1, [](CompB& compB) -> void { + compB.value = 3.0f; + }); + ASSERT_EQ(observer.Size(), 2); + expected = { entity0, entity1 }; + for (const auto e : expected) { + ASSERT_TRUE(expected.contains(e)); + } +} + +TEST(ECSTest, ECRegistryCopyTest) +{ + ECRegistry registry0; + const auto entity0 = registry0.Create(); + const auto entity1 = registry0.Create(); + registry0.Emplace(entity0, 1); + registry0.Emplace(entity1, 2.0f); + + ECRegistry registry1 = registry0; + ASSERT_EQ(registry1.Get(entity0).value, 1); + ASSERT_EQ(registry1.Get(entity1).value, 2.0f); +} diff --git a/Engine/Source/Runtime/Test/ECSTest.h b/Engine/Source/Runtime/Test/ECSTest.h index 032ae51cf..94dcb58be 100644 --- a/Engine/Source/Runtime/Test/ECSTest.h +++ b/Engine/Source/Runtime/Test/ECSTest.h @@ -18,3 +18,63 @@ struct EClass() CompA { int value; }; + +struct EClass() CompB { + EClassBody(CompB) + + explicit CompB(float inValue) + : value(inValue) + { + } + + float value; +}; + +struct EClass() GCompA { + EClassBody(GCompA) + + explicit GCompA(int inValue) + : value(inValue) + { + } + + int value; +}; + +struct EClass() GCompB { + EClassBody(GCompB) + + explicit GCompB(float inValue) + : value(inValue) + { + } + + float value; +}; + +struct EventCounts { + uint32_t onConstructed; + uint32_t onUpdated; + uint32_t onRemove; + + EventCounts() + : onConstructed(0) + , onUpdated(0) + , onRemove(0) + { + } + + EventCounts(uint32_t inOnConstructed, uint32_t inOnUpdated, uint32_t inOnRemove) + : onConstructed(inOnConstructed) + , onUpdated(inOnUpdated) + , onRemove(inOnRemove) + { + } + + bool operator==(const EventCounts& inRhs) const + { + return onConstructed == inRhs.onConstructed + && onUpdated == inRhs.onUpdated + && onRemove == inRhs.onRemove; + } +}; diff --git a/Engine/Source/Runtime/Test/RuntimeTestModule.cpp b/Engine/Source/Runtime/Test/RuntimeTestModule.cpp index b96708b1f..b87534972 100644 --- a/Engine/Source/Runtime/Test/RuntimeTestModule.cpp +++ b/Engine/Source/Runtime/Test/RuntimeTestModule.cpp @@ -7,7 +7,6 @@ void RuntimeTestModule::OnUnload() { Runtime::EngineHolder::Unload(); - engine.Reset(); } Core::ModuleType RuntimeTestModule::Type() const @@ -17,8 +16,7 @@ Core::ModuleType RuntimeTestModule::Type() const Runtime::Engine* RuntimeTestModule::CreateEngine(const Runtime::EngineInitParams& inParams) { - engine = new Runtime::MinEngine(inParams); - return engine.Get(); + return new Runtime::MinEngine(inParams); } IMPLEMENT_STATIC_MODULE(RuntimeTest, "RuntimeTest", RuntimeTestModule) diff --git a/Engine/Source/Runtime/Test/RuntimeTestModule.h b/Engine/Source/Runtime/Test/RuntimeTestModule.h index 8ab29f481..f47333d26 100644 --- a/Engine/Source/Runtime/Test/RuntimeTestModule.h +++ b/Engine/Source/Runtime/Test/RuntimeTestModule.h @@ -6,12 +6,9 @@ #include -class RuntimeTestModule final : public Runtime::IGameModule { +class RuntimeTestModule final : public Runtime::IEngineModule { public: void OnUnload() override; Core::ModuleType Type() const override; Runtime::Engine* CreateEngine(const Runtime::EngineInitParams& inParams) override; - -private: - Common::UniqueRef engine; }; diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp new file mode 100644 index 000000000..a75fdcb47 --- /dev/null +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -0,0 +1,121 @@ +// +// Created by johnk on 2024/12/25. +// + +#include +#include +#include +#include +#include +using namespace Runtime; + +struct WorldTest : testing::Test { + void SetUp() override + { + EngineInitParams engineInitParams; + engineInitParams.rhiType = RHI::GetAbbrStringByType(RHI::RHIType::dummy); + + EngineHolder::Load("RuntimeTest", engineInitParams); + engine = &EngineHolder::Get(); + } + + void TearDown() override + { + EngineHolder::Unload(); + } + + Engine* engine; +}; + +Position::Position() + : x(0.0f) + , y(0.0f) +{ +} + +Position::Position(float inX, float inY) + : x(inX) + , y(inY) +{ +} + +bool Position::operator==(const Position& inRhs) const +{ + return CompareNumber(x, inRhs.x) + && CompareNumber(y, inRhs.y); +} + +Velocity::Velocity() + : x(0.0f) + , y(0.0f) +{ +} + +Velocity::Velocity(float inX, float inY) + : x(inX) + , y(inY) +{ +} + +bool Velocity::operator==(const Velocity& inRhs) const +{ + return CompareNumber(x, inRhs.x) + && CompareNumber(y, inRhs.y); +} + +BasicTest_MotionSystem::BasicTest_MotionSystem(ECRegistry& inRegistry) + : System(inRegistry) +{ + auto entity0 = registry.Create(); + registry.Emplace(entity0, 1.0f, 2.0f); + registry.Emplace(entity0, 0.5f, 1.0f); + + auto entity1 = registry.Create(); + registry.Emplace(entity1, 0.0f, 1.0f); + registry.Emplace(entity1, 1.0f, 0.0f); + + auto& [entities] = registry.GEmplace(); + entities = { + { entity0, Position(1.5f, 3.0f) }, + { entity1, Position(1.0f, 1.0f) } + }; +} + +BasicTest_MotionSystem::~BasicTest_MotionSystem() = default; + +void BasicTest_MotionSystem::Tick(float inDeltaTimeMs) +{ + auto& [entities] = registry.GGet(); + + const auto view = registry.View(); + view.Each([&](Entity entity, Position& position, Velocity& velocity) -> void { + auto& expectPos = entities.at(entity); + position.x += velocity.x; + position.y += velocity.y; + ASSERT_EQ(expectPos, position); + + expectPos.x = position.x + velocity.x; + expectPos.y = position.y + velocity.y; + }); + registry.GNotifyUpdated(); +} + +TEST_F(WorldTest, BasicTest) +{ + SystemGraph systemGraph; + auto& mainGroup = systemGraph.AddGroup("MainGroup"); + mainGroup.EmplaceSystem(&BasicTest_MotionSystem::GetStaticClass()); + + const auto world = engine->CreateWorld(); + world->SetSystemGraph(systemGraph); + world->Play(); + for (auto i = 0; i < 5; i++) { + engine->Tick(0.0167f); + } + world->Stop(); +} + +TEST_F(WorldTest, ConcurrentTest) +{ + // TODO +} diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h new file mode 100644 index 000000000..683576318 --- /dev/null +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -0,0 +1,50 @@ +// +// Created by johnk on 2024/12/25. +// + +#pragma once + +#include + +#include +#include +#include + +struct EClass() Position { + EClassBody(Position) + + Position(); + Position(float inX, float inY); + + bool operator==(const Position& inRhs) const; + + float x; + float y; +}; + +struct EClass() Velocity { + EClassBody(Velocity) + + Velocity(); + Velocity(float inX, float inY); + + bool operator==(const Velocity& inRhs) const; + + float x; + float y; +}; + +struct EClass() BasicTest_ExpectVerifyResult { + EClassBody(BasicTest_ExpectVerifyResult) + + std::unordered_map entities; +}; + +class EClass() BasicTest_MotionSystem : public Runtime::System { + EClassBody(BasicTest_MotionSystem) + + explicit BasicTest_MotionSystem(Runtime::ECRegistry& inRegistry); + ~BasicTest_MotionSystem() override; + + void Tick(float inDeltaTimeMs) override; +}; diff --git a/Sample/Base/Application.cpp b/Sample/Base/Application.cpp index 4db3f16b0..e9dbec2b3 100644 --- a/Sample/Base/Application.cpp +++ b/Sample/Base/Application.cpp @@ -47,7 +47,7 @@ bool Application::Initialize(int argc, char* argv[]) return false; } - rhiType = RHI::RHIAbbrStringToRHIType(rhiString); + rhiType = RHI::GetRHITypeByAbbrString(rhiString); instance = RHI::Instance::GetByType(rhiType); return true; From 06a53fd5fc5f9cc7d4d7a165d893285ae2fd563e Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 29 Dec 2024 01:33:14 +0800 Subject: [PATCH 02/12] feat: upgrade rapidjson and libclang version --- Script/Windows/ComputeFileSha256.ps1 | 3 --- ThirdParty/CMakeLists.txt | 12 ++++++------ 2 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 Script/Windows/ComputeFileSha256.ps1 diff --git a/Script/Windows/ComputeFileSha256.ps1 b/Script/Windows/ComputeFileSha256.ps1 deleted file mode 100644 index e41e0a8b1..000000000 --- a/Script/Windows/ComputeFileSha256.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -param($file) - -Get-FileHash $file -Algorithm SHA256 diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index db8564801..0561b3fb1 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -142,11 +142,11 @@ Add3rdBinaryPackage( NAME llvm-clang ARCH VERSION - Windows-AMD64 17.0.4 - Darwin-arm64 15.0.7 + Windows-AMD64 19.1.6 + Darwin-arm64 19.1.6 HASH - Windows-AMD64 3443a2259d092797521bde0c4b6e402ddeca4beb0abd87274ece91ac44b178ce - Darwin-arm64 99a4884945674163374d99c2220cadbfe20a947b1217193140c6b6638a3b0627 + Windows-AMD64 f68b922c87a99b22c0b53a5cbd55db86bd3870c16c4e9060efaecfb9ce49e726 + Darwin-arm64 08fdf1b6208823acadc23027fda1f12e5171101ec05fa526b545088be31fe19d INCLUDE $/include LINK $/lib LIB @@ -262,7 +262,7 @@ set(Qt6Core_VERSION_MAJOR 6 CACHE STRING "" FORCE) Add3rdHeaderOnlyPackage( NAME rapidjson PLATFORM All - VERSION 1.1.0 - HASH c19c92601374a161b0355ccb73f02b31076c70d4446e5ad53c8b80263a9c900c + VERSION d621dc9 + HASH 696f6ca1ecca9d13170c0a47eda66a3015bcf02a7b4bdd23f574ea302eb4bf3e INCLUDE $/include ) From 8580de10a1d3dcbce1ae5df7e1d52595bcddddd4 Mon Sep 17 00:00:00 2001 From: John Kindem <461425614@qq.com> Date: Sun, 29 Dec 2024 01:58:05 +0800 Subject: [PATCH 03/12] feat: upgrade vulkan sdk --- ThirdParty/CMakeLists.txt | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 0561b3fb1..66928d5a6 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -8,13 +8,13 @@ Add3rdHeaderOnlyPackage( ) # VulkanSDK -set(VULKAN_SDK_VERSION 1.3.243.0) +set(VULKAN_SDK_VERSION 1.3.296.0) Add3rdBinaryPackage( NAME VulkanSDK VERSION ${VULKAN_SDK_VERSION} HASH - Windows 23ded0e6155a8ea265da84bd62f7a45cc3fc637fb1eeba61a5b9430fa704e4b5 - Darwin a5c63a4f29984540efa00190240d31b59539413cf4783792bd9f53207f4f7d07 + Windows 27b8344a5b1333222d55c9c107914dba1cc9beb788b207e087c27dc7b8762816 + Darwin a792aaad3937a694a4cb853d2fbb3fa7025ba3754bedd52799e687a4c254129c INCLUDE Windows $/Include Darwin $/macOS/include @@ -41,9 +41,23 @@ if (NOT ${CI}) execute_process(COMMAND PowerShell -Command "Start-Process reg -ArgumentList 'add HKEY_LOCAL_MACHINE\\SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers /v ${VALIDATION_LAYER_JSON} /t REG_DWORD /d 0' -Verb RunAs") endif () else (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") - # check drivers + # new version of vulkaninfo application use volk to perform dynamic loading, which need libvulkan.dylib in working directory or system, + # so if vulkaninfo print initialized failed, we need copy vulkan dynamic lib to working directory set(PLATFORM_VULKAN_SDK_DIR ${CMAKE_SOURCE_DIR}/ThirdParty/Lib/VulkanSDK-Darwin-${VULKAN_SDK_VERSION}/macOS) - execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + string(REGEX MATCH "Failed to initialize" MATCH_RESULT ${VULKAN_INFO}) + list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) + if (${MATCH_RESULT_LENGTH} GREATER 0) + set(SRC_FILE ${PLATFORM_VULKAN_SDK_DIR}/lib/libvulkan.dylib) + set(DST_FILE ${PLATFORM_VULKAN_SDK_DIR}/bin/libvulkan.dylib) + message("vulkaninfo initialized failed, perform vulkan dynamic library copy: ${SRC_FILE} -> ${DST_FILE}") + file(COPY_FILE ${SRC_FILE} ${DST_FILE} ONLY_IF_DIFFERENT) + else () + message("vulkaninfo test success") + endif () + + # check drivers + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) string(REGEX MATCH "ERROR_INCOMPATIBLE_DRIVER" MATCH_RESULT ${VULKAN_INFO}) list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) if (${MATCH_RESULT_LENGTH} GREATER 0) @@ -65,7 +79,7 @@ if (NOT ${CI}) endif () # check layers - execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) + execute_process(COMMAND ${PLATFORM_VULKAN_SDK_DIR}/bin/vulkaninfo WORKING_DIRECTORY ${PLATFORM_VULKAN_SDK_DIR}/bin OUTPUT_VARIABLE VULKAN_INFO ERROR_VARIABLE VULKAN_INFO) string(REGEX MATCH "Layers:\n=======" MATCH_RESULT ${VULKAN_INFO}) list(LENGTH MATCH_RESULT MATCH_RESULT_LENGTH) if (${MATCH_RESULT_LENGTH} GREATER 0) From ffc2e3b3d2e2896323446b36f9b99e189c666114 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 29 Dec 2024 18:27:02 +0800 Subject: [PATCH 04/12] refactor: vulkan extension refactor --- .../RHI-Vulkan/Include/RHI/Vulkan/Instance.h | 2 - Engine/Source/RHI-Vulkan/Src/Device.cpp | 12 ++--- Engine/Source/RHI-Vulkan/Src/Instance.cpp | 52 +++++++++---------- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h index 626c0167f..a7a16121f 100644 --- a/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h +++ b/Engine/Source/RHI-Vulkan/Include/RHI/Vulkan/Instance.h @@ -54,8 +54,6 @@ namespace RHI::Vulkan { #endif VkInstance nativeInstance; std::vector nativePhysicalDevices; - std::vector vkEnabledExtensionNames; - std::vector vkEnabledLayerNames; std::vector> gpus; std::unordered_map dynamicFuncPointers; }; diff --git a/Engine/Source/RHI-Vulkan/Src/Device.cpp b/Engine/Source/RHI-Vulkan/Src/Device.cpp index c5c15a386..fb9080ab5 100644 --- a/Engine/Source/RHI-Vulkan/Src/Device.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Device.cpp @@ -24,7 +24,7 @@ #include namespace RHI::Vulkan { - const std::vector DEVICE_EXTENSIONS = { + const std::vector requiredExtensions = { "VK_KHR_swapchain", "VK_KHR_dynamic_rendering", "VK_KHR_depth_stencil_resolve", @@ -34,7 +34,7 @@ namespace RHI::Vulkan { #endif }; - const std::vector VALIDATION_LAYERS = { + const std::vector requiredValidationLayers = { "VK_LAYER_KHRONOS_validation" }; } @@ -259,12 +259,12 @@ namespace RHI::Vulkan { dynamicRenderingFeatures.dynamicRendering = VK_TRUE; deviceCreateInfo.pNext = &dynamicRenderingFeatures; - deviceCreateInfo.ppEnabledExtensionNames = DEVICE_EXTENSIONS.data(); - deviceCreateInfo.enabledExtensionCount = static_cast(DEVICE_EXTENSIONS.size()); + deviceCreateInfo.ppEnabledExtensionNames = requiredExtensions.data(); + deviceCreateInfo.enabledExtensionCount = static_cast(requiredExtensions.size()); #ifdef BUILD_CONFIG_DEBUG - deviceCreateInfo.enabledLayerCount = static_cast(VALIDATION_LAYERS.size()); - deviceCreateInfo.ppEnabledLayerNames = VALIDATION_LAYERS.data(); + deviceCreateInfo.enabledLayerCount = static_cast(requiredValidationLayers.size()); + deviceCreateInfo.ppEnabledLayerNames = requiredValidationLayers.data(); #endif Assert(vkCreateDevice(gpu.GetNative(), &deviceCreateInfo, nullptr, &nativeDevice) == VK_SUCCESS); diff --git a/Engine/Source/RHI-Vulkan/Src/Instance.cpp b/Engine/Source/RHI-Vulkan/Src/Instance.cpp index e0ecde4b6..a3a5ebcf0 100644 --- a/Engine/Source/RHI-Vulkan/Src/Instance.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Instance.cpp @@ -10,6 +10,25 @@ #include namespace RHI::Vulkan { + static std::vector requiredLayerNames = { + "VK_LAYER_KHRONOS_validation" + }; + + static std::vector requiredExtensionNames = { + "VK_KHR_surface", +#if PLATFORM_WINDOWS + "VK_KHR_win32_surface", +#elif PLATFORM_MACOS + "VK_MVK_macos_surface", + "VK_EXT_metal_surface", + "VK_KHR_portability_enumeration", + "VK_KHR_get_physical_device_properties2", +#endif +#if BUILD_CONFIG_DEBUG + "VK_EXT_debug_utils" +#endif + }; + #if BUILD_CONFIG_DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, @@ -66,10 +85,6 @@ namespace RHI::Vulkan { #if BUILD_CONFIG_DEBUG void VulkanInstance::PrepareLayers() { - static std::vector requiredLayerNames = { - "VK_LAYER_KHRONOS_validation" - }; - uint32_t supportedLayerCount = 0; vkEnumerateInstanceLayerProperties(&supportedLayerCount, nullptr); std::vector supportedLayers(supportedLayerCount); @@ -81,30 +96,14 @@ namespace RHI::Vulkan { [&requiredLayerName](const auto& elem) -> bool { return std::string(requiredLayerName) == elem.layerName; } ); iter == supportedLayers.end()) { - QuickFailWithReason("not found required vulkan layers"); + QuickFailWithReason("required vulkan layers is missing"); } - vkEnabledLayerNames.emplace_back(requiredLayerName); } } #endif void VulkanInstance::PrepareExtensions() { - static std::vector requiredExtensionNames = { - VK_KHR_SURFACE_EXTENSION_NAME, -#if PLATFORM_WINDOWS - "VK_KHR_win32_surface", -#elif PLATFORM_MACOS - "VK_MVK_macos_surface", - "VK_EXT_metal_surface", - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, -#endif -#if BUILD_CONFIG_DEBUG - VK_EXT_DEBUG_UTILS_EXTENSION_NAME -#endif - }; - uint32_t supportedExtensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &supportedExtensionCount, nullptr); std::vector supportedExtensions(supportedExtensionCount); @@ -116,9 +115,8 @@ namespace RHI::Vulkan { [&requiredExtensionName](const auto& elem) -> bool { return std::string(requiredExtensionName) == elem.extensionName; } ); iter == supportedExtensions.end()) { - continue; + QuickFailWithReason("required vulkan extensions is not support"); } - vkEnabledExtensionNames.emplace_back(requiredExtensionName); } } @@ -134,11 +132,11 @@ namespace RHI::Vulkan { VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &applicationInfo; - createInfo.enabledExtensionCount = vkEnabledExtensionNames.size(); - createInfo.ppEnabledExtensionNames = vkEnabledExtensionNames.data(); + createInfo.enabledExtensionCount = requiredExtensionNames.size(); + createInfo.ppEnabledExtensionNames = requiredExtensionNames.data(); #if BUILD_CONFIG_DEBUG - createInfo.enabledLayerCount = vkEnabledLayerNames.size(); - createInfo.ppEnabledLayerNames = vkEnabledLayerNames.data(); + createInfo.enabledLayerCount = requiredLayerNames.size(); + createInfo.ppEnabledLayerNames = requiredLayerNames.data(); VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; PopulateDebugMessengerCreateInfo(debugCreateInfo); From b010f2232991e69e2cd6ca8a1b87afdc1e11818d Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 29 Dec 2024 18:41:35 +0800 Subject: [PATCH 05/12] fix: macos vulkan rendering issue --- Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp | 6 ++++++ Engine/Source/RHI-Vulkan/Src/Device.cpp | 13 +++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp b/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp index e68df1c58..c219f1688 100644 --- a/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp +++ b/Engine/Source/RHI-Vulkan/Src/CommandRecorder.cpp @@ -471,7 +471,13 @@ namespace RHI::Vulkan { void VulkanRasterPassCommandRecorder::SetPrimitiveTopology(PrimitiveTopology inPrimitiveTopology) { +#if PLATFORM_MACOS + // MoltenVK not support use vkCmdSetPrimitiveTopology() directly current + auto* pfn = device.GetGpu().GetInstance().FindOrGetTypedDynamicFuncPointer("vkCmdSetPrimitiveTopologyEXT"); + pfn(commandBuffer.GetNative(), EnumCast(inPrimitiveTopology)); +#else vkCmdSetPrimitiveTopology(commandBuffer.GetNative(), EnumCast(inPrimitiveTopology)); +#endif } void VulkanRasterPassCommandRecorder::SetBlendConstant(const float *inConstants) diff --git a/Engine/Source/RHI-Vulkan/Src/Device.cpp b/Engine/Source/RHI-Vulkan/Src/Device.cpp index fb9080ab5..1814a48ad 100644 --- a/Engine/Source/RHI-Vulkan/Src/Device.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Device.cpp @@ -30,7 +30,8 @@ namespace RHI::Vulkan { "VK_KHR_depth_stencil_resolve", "VK_KHR_create_renderpass2", #if PLATFORM_MACOS - "VK_KHR_portability_subset" + "VK_KHR_portability_subset", + "VK_EXT_extended_dynamic_state" #endif }; @@ -262,7 +263,15 @@ namespace RHI::Vulkan { deviceCreateInfo.ppEnabledExtensionNames = requiredExtensions.data(); deviceCreateInfo.enabledExtensionCount = static_cast(requiredExtensions.size()); -#ifdef BUILD_CONFIG_DEBUG +#if PLATFORM_MACOS + // MoltenVK not support use vkCmdSetPrimitiveTopology() directly current + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures = {}; + extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + extendedDynamicStateFeatures.extendedDynamicState = VK_TRUE; + dynamicRenderingFeatures.pNext = &extendedDynamicStateFeatures; +#endif + +#if BUILD_CONFIG_DEBUG deviceCreateInfo.enabledLayerCount = static_cast(requiredValidationLayers.size()); deviceCreateInfo.ppEnabledLayerNames = requiredValidationLayers.data(); #endif From 9b56a8a6167874226703028a5ebeb250f3232fd7 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 29 Dec 2024 18:52:05 +0800 Subject: [PATCH 06/12] refactor: use metal surface instead molkenvk surface for macOS platform --- Engine/Source/RHI-Vulkan/Src/Instance.cpp | 1 - .../Source/RHI-Vulkan/Src/Platform/MacosSurface.mm | 12 +++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Engine/Source/RHI-Vulkan/Src/Instance.cpp b/Engine/Source/RHI-Vulkan/Src/Instance.cpp index a3a5ebcf0..c19574d3d 100644 --- a/Engine/Source/RHI-Vulkan/Src/Instance.cpp +++ b/Engine/Source/RHI-Vulkan/Src/Instance.cpp @@ -19,7 +19,6 @@ namespace RHI::Vulkan { #if PLATFORM_WINDOWS "VK_KHR_win32_surface", #elif PLATFORM_MACOS - "VK_MVK_macos_surface", "VK_EXT_metal_surface", "VK_KHR_portability_enumeration", "VK_KHR_get_physical_device_properties2", diff --git a/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm b/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm index 88f8a03f9..65c3a8d8c 100644 --- a/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm +++ b/Engine/Source/RHI-Vulkan/Src/Platform/MacosSurface.mm @@ -8,7 +8,7 @@ #include #include -#define VK_USE_PLATFORM_MACOS_MVK +#define VK_USE_PLATFORM_METAL_EXT #include namespace RHI::Vulkan { @@ -22,14 +22,12 @@ VkSurfaceKHR CreateNativeSurface(const VkInstance& instance, const SurfaceCreate [view setLayer: layer]; [view setWantsLayer: YES]; - VkMacOSSurfaceCreateInfoMVK surfaceInfo = {}; - surfaceInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; - surfaceInfo.pView = view; - surfaceInfo.pNext = nullptr; - surfaceInfo.flags = 0; + VkMetalSurfaceCreateInfoEXT surfaceInfo = {}; + surfaceInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + surfaceInfo.pLayer = static_cast(layer); VkSurfaceKHR surface = VK_NULL_HANDLE; - vkCreateMacOSSurfaceMVK(instance, &surfaceInfo, nullptr, &surface); + vkCreateMetalSurfaceEXT(instance, &surfaceInfo, nullptr, &surface); return surface; } } From 2c384bcff5ee4850f6fd615dac3b1a0116eba8f1 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Sun, 29 Dec 2024 19:13:07 +0800 Subject: [PATCH 07/12] feat: new gameplay framework --- Engine/Source/Runtime/Include/Runtime/ECS.h | 71 ++++++++++++++++---- Engine/Source/Runtime/Src/ECS.cpp | 73 +++++++++++++-------- Engine/Source/Runtime/Test/WorldTest.cpp | 67 ++++++++++++++++++- Engine/Source/Runtime/Test/WorldTest.h | 36 ++++++++++ 4 files changed, 207 insertions(+), 40 deletions(-) diff --git a/Engine/Source/Runtime/Include/Runtime/ECS.h b/Engine/Source/Runtime/Include/Runtime/ECS.h index 1d1d719e3..51f6b0fa0 100644 --- a/Engine/Source/Runtime/Include/Runtime/ECS.h +++ b/Engine/Source/Runtime/Include/Runtime/ECS.h @@ -458,21 +458,35 @@ namespace Runtime { std::unordered_map globalCompEvents; }; + enum class SystemExecuteStrategy : uint8_t { + sequential, + concurrent, + max + }; + class RUNTIME_API SystemGroup { public: - explicit SystemGroup(std::string inName); - - Internal::SystemFactory& EmplaceSystem(SystemClass inClass); - void RemoveSystem(SystemClass inClass); - bool HasSystem(SystemClass inClass) const; - Internal::SystemFactory& GetSystem(SystemClass inClass); - const Internal::SystemFactory& GetSystem(SystemClass inClass) const; + explicit SystemGroup(std::string inName, SystemExecuteStrategy inStrategy); + + template Internal::SystemFactory& EmplaceSystem(); + template void RemoveSystem(); + template bool HasSystem() const; + template Internal::SystemFactory& GetSystem(); + template const Internal::SystemFactory& GetSystem() const; + + Internal::SystemFactory& EmplaceSystemDyn(SystemClass inClass); + void RemoveSystemDyn(SystemClass inClass); + bool HasSystemDyn(SystemClass inClass) const; + Internal::SystemFactory& GetSystemDyn(SystemClass inClass); + const Internal::SystemFactory& GetSystemDyn(SystemClass inClass) const; auto GetSystems(); auto GetSystems() const; const std::string& GetName() const; + SystemExecuteStrategy GetStrategy() const; private: std::string name; + SystemExecuteStrategy strategy; std::unordered_map systems; }; @@ -480,7 +494,7 @@ namespace Runtime { public: SystemGraph(); - SystemGroup& AddGroup(const std::string& inName); + SystemGroup& AddGroup(const std::string& inName, SystemExecuteStrategy inStrategy); void RemoveGroup(const std::string& inName); bool HasGroup(const std::string& inName) const; SystemGroup& GetGroup(const std::string& inName); @@ -500,13 +514,18 @@ namespace Runtime { const Internal::SystemFactory& factory; Common::UniqueRef instance; }; - using ActionFunc = std::function; - void ParallelPerformAction(const ActionFunc& inActionFunc); + struct SystemGroupContext { + std::vector systems; + SystemExecuteStrategy strategy; + }; friend class SystemGraphExecutor; + using ActionFunc = std::function; + + void ParallelPerformAction(const ActionFunc& inActionFunc); - std::vector> systemGraph; + std::vector systemGraph; }; class SystemGraphExecutor { @@ -984,4 +1003,34 @@ namespace Runtime { { GNotifyRemoveDyn(Internal::GetClass()); } + + template + Internal::SystemFactory& SystemGroup::EmplaceSystem() + { + return EmplaceSystemDyn(Internal::GetClass()); + } + + template + void SystemGroup::RemoveSystem() + { + RemoveSystemDyn(Internal::GetClass()); + } + + template + bool SystemGroup::HasSystem() const + { + return HasSystemDyn(Internal::GetClass()); + } + + template + Internal::SystemFactory& SystemGroup::GetSystem() + { + return GetSystemDyn(Internal::GetClass()); + } + + template + const Internal::SystemFactory& SystemGroup::GetSystem() const + { + return GetSystemDyn(Internal::GetClass()); + } } // namespace Runtime diff --git a/Engine/Source/Runtime/Src/ECS.cpp b/Engine/Source/Runtime/Src/ECS.cpp index c81cb0b8d..707968410 100644 --- a/Engine/Source/Runtime/Src/ECS.cpp +++ b/Engine/Source/Runtime/Src/ECS.cpp @@ -830,33 +830,34 @@ namespace Runtime { return globalCompEvents[inClass]; } - SystemGroup::SystemGroup(std::string inName) + SystemGroup::SystemGroup(std::string inName, SystemExecuteStrategy inStrategy) : name(std::move(inName)) + , strategy(inStrategy) { } - Internal::SystemFactory& SystemGroup::EmplaceSystem(SystemClass inClass) + Internal::SystemFactory& SystemGroup::EmplaceSystemDyn(SystemClass inClass) { systems.emplace(inClass, Internal::SystemFactory(inClass)); return systems.at(inClass); } - void SystemGroup::RemoveSystem(SystemClass inClass) + void SystemGroup::RemoveSystemDyn(SystemClass inClass) { systems.erase(inClass); } - bool SystemGroup::HasSystem(SystemClass inClass) const + bool SystemGroup::HasSystemDyn(SystemClass inClass) const { return systems.contains(inClass); } - Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) + Internal::SystemFactory& SystemGroup::GetSystemDyn(SystemClass inClass) { return systems.at(inClass); } - const Internal::SystemFactory& SystemGroup::GetSystem(SystemClass inClass) const + const Internal::SystemFactory& SystemGroup::GetSystemDyn(SystemClass inClass) const { return systems.at(inClass); } @@ -876,11 +877,16 @@ namespace Runtime { return name; } + SystemExecuteStrategy SystemGroup::GetStrategy() const + { + return strategy; + } + SystemGraph::SystemGraph() = default; - SystemGroup& SystemGraph::AddGroup(const std::string& inName) + SystemGroup& SystemGraph::AddGroup(const std::string& inName, SystemExecuteStrategy inStrategy) { - return systemGroups.emplace_back(inName); + return systemGroups.emplace_back(inName, inStrategy); } void SystemGraph::RemoveGroup(const std::string& inName) @@ -935,12 +941,13 @@ namespace Runtime { systemGraph.reserve(systemGroups.size()); for (const auto& group : systemGroups) { - auto& contexts = systemGraph.emplace_back(); + auto& [systemContexts, strategy] = systemGraph.emplace_back(); const auto& factories = group.GetSystems(); - contexts.reserve(factories.size()); + strategy = group.GetStrategy(); + systemContexts.reserve(factories.size()); for (const auto& factory : group.GetSystems()) { - contexts.emplace_back(factory, nullptr); + systemContexts.emplace_back(factory, nullptr); } } } @@ -950,22 +957,36 @@ namespace Runtime { tf::Taskflow taskFlow; auto lastBarrier = taskFlow.emplace([]() -> void {}); - for (auto& contexts : systemGraph) { - std::vector tasks; - tasks.reserve(contexts.size()); - - for (auto& context : contexts) { - tasks.emplace_back(taskFlow.emplace([&]() -> void { - inActionFunc(context); - })); - tasks.back().succeed(lastBarrier); - } - - auto barrier = taskFlow.emplace([]() -> void {}); - for (const auto& task : tasks) { - barrier.succeed(task); + for (auto& groupContext : systemGraph) { + if (groupContext.strategy == SystemExecuteStrategy::sequential) { + tf::Task lastTask = lastBarrier; + for (auto& systemContext : groupContext.systems) { + auto task = taskFlow.emplace([&]() -> void { + inActionFunc(systemContext); + }); + task.succeed(lastTask); + lastTask = task; + } + lastBarrier = lastTask; + } else if (groupContext.strategy == SystemExecuteStrategy::concurrent) { + std::vector tasks; + tasks.reserve(groupContext.systems.size()); + + for (auto& systemContext : groupContext.systems) { + tasks.emplace_back(taskFlow.emplace([&]() -> void { + inActionFunc(systemContext); + })); + tasks.back().succeed(lastBarrier); + } + + auto barrier = taskFlow.emplace([]() -> void {}); + for (const auto& task : tasks) { + barrier.succeed(task); + } + lastBarrier = barrier; + } else { + QuickFail(); } - lastBarrier = barrier; } tf::Executor executor; diff --git a/Engine/Source/Runtime/Test/WorldTest.cpp b/Engine/Source/Runtime/Test/WorldTest.cpp index a75fdcb47..a4dba8da1 100644 --- a/Engine/Source/Runtime/Test/WorldTest.cpp +++ b/Engine/Source/Runtime/Test/WorldTest.cpp @@ -103,8 +103,8 @@ void BasicTest_MotionSystem::Tick(float inDeltaTimeMs) TEST_F(WorldTest, BasicTest) { SystemGraph systemGraph; - auto& mainGroup = systemGraph.AddGroup("MainGroup"); - mainGroup.EmplaceSystem(&BasicTest_MotionSystem::GetStaticClass()); + auto& mainGroup = systemGraph.AddGroup("MainGroup", SystemExecuteStrategy::sequential); + mainGroup.EmplaceSystemDyn(&BasicTest_MotionSystem::GetStaticClass()); const auto world = engine->CreateWorld(); world->SetSystemGraph(systemGraph); @@ -115,7 +115,68 @@ TEST_F(WorldTest, BasicTest) world->Stop(); } +ConcurrentTest_SystemA::ConcurrentTest_SystemA(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ +} + +ConcurrentTest_SystemA::~ConcurrentTest_SystemA() = default; + +void ConcurrentTest_SystemA::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.a = 1; +} + +ConcurrentTest_SystemB::ConcurrentTest_SystemB(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ +} + +ConcurrentTest_SystemB::~ConcurrentTest_SystemB() = default; + +void ConcurrentTest_SystemB::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.b = 2; +} + +ConcurrentTest_VerifySystem::ConcurrentTest_VerifySystem(Runtime::ECRegistry& inRegistry) + : System(inRegistry) +{ + auto& context = registry.GEmplace(); + context.a = 0; + context.b = 0; + context.sum = 0; + context.tickCount = 0; +} + +ConcurrentTest_VerifySystem::~ConcurrentTest_VerifySystem() = default; + +void ConcurrentTest_VerifySystem::Tick(float inDeltaTimeMs) +{ + auto& context = registry.GGet(); + context.sum = context.sum + context.a + context.b; + context.a = 0; + context.b = 0; + context.tickCount++; + ASSERT_EQ(context.sum, 3 * context.tickCount); +} + TEST_F(WorldTest, ConcurrentTest) { - // TODO + SystemGraph systemGraph; + auto& ConcurrentGroup = systemGraph.AddGroup("ConcurrentGroup", SystemExecuteStrategy::concurrent); + ConcurrentGroup.EmplaceSystem(); + ConcurrentGroup.EmplaceSystem(); + auto& verifyGroup = systemGraph.AddGroup("VerifyGroup", SystemExecuteStrategy::sequential); + verifyGroup.EmplaceSystem(); + + const auto world = engine->CreateWorld(); + world->SetSystemGraph(systemGraph); + world->Play(); + for (auto i = 0; i < 5; i++) { + engine->Tick(0.0167f); + } + world->Stop(); } diff --git a/Engine/Source/Runtime/Test/WorldTest.h b/Engine/Source/Runtime/Test/WorldTest.h index 683576318..8e3936ed7 100644 --- a/Engine/Source/Runtime/Test/WorldTest.h +++ b/Engine/Source/Runtime/Test/WorldTest.h @@ -48,3 +48,39 @@ class EClass() BasicTest_MotionSystem : public Runtime::System { void Tick(float inDeltaTimeMs) override; }; + +struct EClass() ConcurrentTest_Context { + EClassBody(ConcurrentTest_Context) + + uint32_t a; + uint32_t b; + uint32_t sum; + uint32_t tickCount; +}; + +struct EClass() ConcurrentTest_SystemA : public Runtime::System { + EClassBody(ConcurrentTest_SystemA) + + explicit ConcurrentTest_SystemA(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_SystemA() override; + + void Tick(float inDeltaTimeMs) override; +}; + +struct EClass() ConcurrentTest_SystemB : public Runtime::System { + EClassBody(ConcurrentTest_SystemB) + + explicit ConcurrentTest_SystemB(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_SystemB() override; + + void Tick(float inDeltaTimeMs) override; +}; + +struct EClass() ConcurrentTest_VerifySystem : public Runtime::System { + EClassBody(ConcurrentTest_VerifySystem) + + explicit ConcurrentTest_VerifySystem(Runtime::ECRegistry& inRegistry); + ~ConcurrentTest_VerifySystem() override; + + void Tick(float inDeltaTimeMs) override; +}; From 9a5380c39e25e19b5cd17cb6f1db09352ec7e596 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Mon, 30 Dec 2024 22:05:15 +0800 Subject: [PATCH 08/12] fix: editor exit with crash issue --- Editor/Source/Src/Core.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Editor/Source/Src/Core.cpp b/Editor/Source/Src/Core.cpp index d958b563a..e0760c60e 100644 --- a/Editor/Source/Src/Core.cpp +++ b/Editor/Source/Src/Core.cpp @@ -35,6 +35,8 @@ namespace Editor { void Core::Cleanup() // NOLINT { + Runtime::EngineHolder::Unload(); + engine = nullptr; ::Core::ModuleManager::Get().Unload("Runtime"); } From 212722fc8cbf75acb1b299eb2ad2623cba71758f Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Mon, 30 Dec 2024 23:31:14 +0800 Subject: [PATCH 09/12] feat: project launcher update --- .../Source/Include/Editor/Widget/Launcher.h | 8 +++--- Editor/Source/Src/Widget/Launcher.cpp | 28 +++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Editor/Source/Include/Editor/Widget/Launcher.h b/Editor/Source/Include/Editor/Widget/Launcher.h index 0c5f27c5b..465ffca87 100644 --- a/Editor/Source/Include/Editor/Widget/Launcher.h +++ b/Editor/Source/Include/Editor/Widget/Launcher.h @@ -5,7 +5,7 @@ #pragma once #include -#include +#include namespace Editor { class Launcher final : public QWidget { @@ -15,9 +15,9 @@ namespace Editor { Launcher(); void SetWindowProperties(); - void CreateMainCol(); - void CreateLogoRow() const; + void CreateMainRow(); + void CreateMenuCol() const; - QVBoxLayout* mainCol; + QHBoxLayout* mainRow; }; } diff --git a/Editor/Source/Src/Widget/Launcher.cpp b/Editor/Source/Src/Widget/Launcher.cpp index 216a44a51..fdb097212 100644 --- a/Editor/Source/Src/Widget/Launcher.cpp +++ b/Editor/Source/Src/Widget/Launcher.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include // NOLINT @@ -14,8 +15,8 @@ namespace Editor { Launcher::Launcher() { SetWindowProperties(); - CreateMainCol(); - CreateLogoRow(); + CreateMainRow(); + CreateMenuCol(); } void Launcher::SetWindowProperties() @@ -29,21 +30,24 @@ namespace Editor { setPalette(pal); } - void Launcher::CreateMainCol() + void Launcher::CreateMainRow() { - mainCol = new QVBoxLayout(); - setLayout(mainCol); + mainRow = new QHBoxLayout(); + mainRow->setContentsMargins(QMargins(50, 50, 50, 50)); + setLayout(mainRow); } - void Launcher::CreateLogoRow() const + void Launcher::CreateMenuCol() const { - auto* logoRow = new QHBoxLayout(); - logoRow->setContentsMargins(QMargins(0, 50, 0, 0)); - mainCol->addLayout(logoRow); + auto* menuCol = new QVBoxLayout(); + mainRow->addLayout(menuCol); + + auto* logoAndVersionRow = new QHBoxLayout(); + menuCol->addLayout(logoAndVersionRow); auto* logoLabel = new QLabel(); - logoLabel->setPixmap(QPixmap(StaticResources::picLogo).scaled(250, 250, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - logoLabel->setAlignment(Qt::AlignHCenter); - mainCol->addWidget(logoLabel); + logoLabel->setPixmap(QPixmap(StaticResources::picLogo).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + logoLabel->setAlignment(Qt::AlignVCenter); + logoAndVersionRow->addWidget(logoLabel); } } From 53b802c6d84934025057ff164cd90708f36540c1 Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Tue, 31 Dec 2024 18:26:05 +0800 Subject: [PATCH 10/12] refactor: do not use find package global for qt --- CMake/ThirdParty.cmake | 30 ++++++++++++++++++++++++++++++ Editor/Resource/logo.png | Bin 17536 -> 0 bytes Editor/Source/CMakeLists.txt | 23 +++++++++++------------ ThirdParty/CMakeLists.txt | 20 ++++++++------------ 4 files changed, 49 insertions(+), 24 deletions(-) delete mode 100644 Editor/Resource/logo.png diff --git a/CMake/ThirdParty.cmake b/CMake/ThirdParty.cmake index 1e8a7cb81..dd14c9483 100644 --- a/CMake/ThirdParty.cmake +++ b/CMake/ThirdParty.cmake @@ -503,3 +503,33 @@ function(Find3rdPackage) ) endif() endfunction() + +function(Setup3rdPackage) + cmake_parse_arguments(PARAMS "" "NAME;PLATFORM;VERSION" "HASH" ${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} + ) + + set(${PARAMS_NAME}_SOURCE_DIR ${SOURCE_DIR}) +endfunction() diff --git a/Editor/Resource/logo.png b/Editor/Resource/logo.png deleted file mode 100644 index daffbafafe4133d78f042bc664a1275e45cd2a80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17536 zcmd3uWnY`m)3<{aibHXSV#TevyHi|)ySqEZoffwO1&TYAP+UTBm*O4>PViFh{I36- zxF6)n`B}-i*`1l4`5uY?q^^L4PKFKu0I-x4WwihRgtY%YXm8+8!h88A003D9C0QvQ z|ANzvw`nH#A=D3BU1nQiAroRG>-4tF8KsJE7c3$(Y`B{l6u42d_R7Axw-}p(#!7za zlDqk0Z0qr-2(XTk=l_{BTCcTi7-#(ckjDNc#WFIB{ZrPDM2brQ8e-1#Y1gw)FY6)} zrqJh#puj-T^J~h50t&(q#fyx_{d3Rj4M?1C&hwWViWLQV=^Ya{?6dS*a(goEUuyxPeFag35 zQsA=$;bFe1i0q$9D#<5EmRDEG2p;2OU$Qx?rs67TRKD>_w1e&pdMpi3PM!)a`5>I4 zA|g|Kz>l9;h@vHnpUSCF>Nmfn2VcFbg`V)6ZdavE7uTRBsVzBo>h#zfjnr1?ayHjv znG2xdnsel;7I9-aL8t9DW=bKb8$Sv;3001u7g}np#WFv_=V>IrHAMFJDba<};ipUt zSi-g?oTbgPJkFM1(4BTCR`-JG*pQa)yxs3U4`k6_W3UP zEsxSWCX6kQf>5KrFkG4$pJsZE;oT;M(L+YM^wA_6TE3?eD#l^UD?_z;Q!dpP={BQ$ zJK#Hiaztd1wC2~UaIylWaxFWoL2Dp3uBKW;(e#0*8FOX=#}` zxNVg|uhCKuo^@`&X!q>&uBW2^*zGH|?9;0HjTM)s(eAhPwW=t8_^K9%jnUJiWz%J} z>Ko`M^Z&k7mMq;>4vpfy!hl7Rga2m>NK2kxz!KLjaq}w00P-Cs0;1Y5swK`3&uvXz ztf|I&l)&-!$<@WSMFrN(v71^agnP;GJ`rTZh%X7Xp=|i^qI77bM|z=y=gQ@~Li0Qv z&aSSZMLz7?&S<#yX*K~YnW_>W#>YM^wT1J#Q^1$<{PgKbcqykZ1(!xVTalhBQJ&n1 zpDPjFmp(z%h9{S4EOSmfGa=?oXPX@jw-_BohBqo|P{Ybb@HDz2bDF(@t=JZbDu{$Q zWM|p*V72q<0k3u~{AKjOOM@WsvCT&Z97+0Qfau1U}`mK+nk?z=ov7v zc}nXlwHeX?EH8JN#wl_K!11aX_m98?B-VCOd9+oGcyh z@xu0e$tMz|jP1Zk8q7CQJJXk<)OGfmy_P^6?>FqY#5p;Fmj!)^IY5-6p&QZ3NweZ5 zAJs=6a^$!uhBx?jbm@@y6yQA*>`T6sJ+h-TXXpB`B|f!+)pL9_+}J!4iOXi1I0H`vAP2psI>rKMH7;x%s`z8{$e(iyAKGm zTjP%&OrJK$%4}GwUfIazZk2pe)LlT0iB*_xsYmL=;H&c#&mR}9b`X@$CPY>&#>Byr zsH^TLUGf3=$2*XDjkBuY9D`DDEdW4+5H3-^>w@YxVHrM@0Mo&nU^cRNF_zzSnd3G| zi7-;c@3Gc~MP$_Z{+b#4T?Wg$1oqd`oTC|@)&F+q_^@c_6zHIczmzk+SIwqh87}$2 zj3sfIX~)0n5u(Q-qWBj{XRJH~WfGIU)xyD>XRJ14%=C^Lt56Eq_@-JX4_#y-^p0{L zp*z(T<#%uY_h-zSH?^gHm=l*qj7wNJIOb?y!C-k7=Yw3u_tF`EE=j9?fED2LkigDO6(qDD?^3b+SwxXj%I@iRy_fp{A0m1Ex<4#YtyPfOgTRKI%^H}*nU4ZtuQb{K$ zYo%A`U!kQoe=J1nVz?Q~jqo4f-SJ?h!u`!2Yun+GbF@C&+-UlwpnmEe)Ge+#6yuzH8D;YuR1s5hg6> zhdo4QMP+Ka$}iU2yaf4!_$}XxE>Yzsr*M&B6J!bdo&H|IlpkyDb|+nr;HjyEAQ>4k zBxF4hBSO&Cjk71;Z2q?ukUa}>vBb}1g+b=s&ENH_`EOeMs^N1CVD)`NQouS@@=RO&Kasb3=z;_36(59lH}`E|Q$KxiKzlG_=zyAz6k`9oIX+|56s#-%n7e%5YCi z)zOaD-p2ehANuhprFch86eP$#Q&Ci-16*otz+Y!?S}yXo?_qR?W`igZ_R{1M`)lO{!MEH1?tS!>c$jL`*Gd zJQ&H6yM#q8Gi0gBDJ!IOSC{WSlyOh3o&LCr+}1ggiM9M(Um3#tTUW7ctIx$ahgWHe zLGiv&z4$H4`+97g=%Zsh>?CdJbi?djW}CrpTVXfCi)^j3f2a78S34h}_VK59Ba%jG z^bU^h?vMhPPCq3hoeYTfJ1duHa7tYwww(m`vit`Aw1Drs&@zL8QkjOe^5cn{zvgUI zg;hE%VYYdUBeH)!1019?_N$s^;|&F3WBWW{@mF}tZL2PAFE6)C&y&eJQfJGQ*#{$h zhbkzwCikuUrq~o$Q85ntHM$haiyX+K*oX)|j`r>kq$zt=wNA%hC%j-+O%`NWZ$wTi z_t*biLnOO1iMCNdMl3BHC?ps^BDDDpTNWJ&?P@y^5SpXP6jJK*D$f2~{&t3{7t}x)vS4-=TmlD>#yXp=n69uwlPZ?%)j(~_Ny$-21FtM<)#p)c+#Ty~A zY|4H^WnG~~V7k&aAY%HS;FGzq9I8xzPbTuzM`4~PRW6boOJM9gtzl zN{*g&pgZ$MU^>mzrqd?;p0qPr6}V`(uxqB7*>R8KI7&=zS?%wY)f8q{n)B{78947&qmgtaqb~kw z-swN0yU`twkeARw1(NbU=5SrIa}ZZi|(IMc&XU&FSz6L7w`X0&DiD)sxcc z_+B+V;eAvIKaa5Z0Hko=*vRGerT=uhaS2zY$_Y-7^SZU{2OS%K)6hJP#_FJ_*EPU3~cy?PI>%=hZ%`)>vOge!gO}M0l#v9erQY&u8R*nYB}5 z(JJYB4GhP`!U|0}8rH6bLSjVr;P1a;L%c_|!AW*mU zV-Y=Af@(QC)C;%y0t**O65{;p1`kV^=Xq-#Yf^@E(^hQAa635gnLb{JBRizqtHI5P z2L8GV?~#gD^UQe&f}Q%;QW_HiHGDDFuFS*f>WbVh3qLV?>gg_isfC*V7C^v9m!nFz zS-pjdwNu1@HV#8HoPgb~^BEgn76R zX^)ozn>^1&Vh3ic5<&TKQ&W?KB@mUh$6rA9J(5O3DJ0%d-zRo}Rx97T^4p$cn2}f* zf~Gy@4j;THT~V}xxthrq=pxiKE~PmmOY?d5RXn!mmtY*b$v_5Kt%MO8E*E=|kSp6=9~u$HyNb z_lvaDw`0Ujc4=@S)kw%kA-MH;d}A$5Uol+z2unQLL`^6yBJlsM4R4jGB61PZwx&lh zBZeSlPr47NvOe*ub%LNyql}JTHriFre-PdJ>3@d2GaE8#g1E#S;>~t==FnaAHcf};R%mUHc=iYV$CsSsET#K4f3fHp#0dV+ zk?CNAV8&)Z^Mm_kLJ38n# zTG@?iGLJLo$X*(Ms%}lO&t)pdIJU1Y8ujP0jaRq}UMuqF2Nd|QZyY`W-o6vYdrk$f3&*X`6c!!qh9tNv!W6!)e9+Lm^sb6BBni z6*&bnRUCTTf5XmXsp)L9i)&$8UUsdhU^b4Yz{5EchhHKx5CwbpyA0+vcv1Rn^^V>H zaneDkRb4dZ=+WTCudX`4vBOj!brdoRp}zWc&#&rycxV6fK$Q(rOhR4y{@Q)HhkDwB z@B8OtBqUS_HO`jOy}ZH)T9hB=OU!omz#s~91zn^{^x*;Rc9(!dQNZ$>xKd{AD}!AO z_)=HCPsha?H9$B+_MlabJt(OU+X{rrZu^sImwEH>tK;CP&lc{`8vQtQDAzlA+LH=f z&C0yjVjXHjz)u{0jV}Fh-%?*zJQ9gO=Gy013N;e-+Ak(<$@|JLaGOh) zr-wZg5@FR9ytI}+cjg{Y{!_k}_qA>$i33CCqTX_K^>UjrEiIQM-eVfjt(o_uC4#xgu!Tu9iKXABUH{ zE%?t|j#bPiuL25|HX){gJ0FI3AIy?NobiNGDlBI!j!I;*+x&}C$KLbNoQh3^@o5R` zhf!j(S_o$f%3h>k&f_GqCJ!fV2a8T0j2|@rH%dn%4Svdl?FP8c^CM+VE+yTN-@Uy> z(Aq_ip;hz2<_gKnPM0ktOdMv#S9QL`gSaFs^^XKf2I}`=PivaJvSS}FCe|EmcVMAn zDF2;HGb3^TBUWh_)WI0Lb|)PTK#^N6IBltFoMRvv3d%yi)SEBnuI?=bvM z;R2_CCf(|GX-7D(|6_&xv33*_*=<-uW71Nb%xCG6X93>)`VH&Zj|ljw3?^GaZPmZLP9`2{>LiW1nuCu<%j2~w*J9(%O1J@VqhDVz z2TkCpwdOfqeb;@b+`?v5t&_19%N{ytHgK&Wh8@b@?Qq+gMB$k9G#^co!Mug!S8%mgxrZ z#s8Y?cY);ABxi|AA~!rev*g&8SPNZY1$Riob5g2xOP1R!vGoKhI=7GBwnPN#rBd7@ zprovy`L9l~eOE9I@OcSSii9iz)zL&F!KWx*xb^?Mha`)C@TJztJ@08_cM-q+?!04d zpF1Y%sL-L(<|-lr2?j-#ki|cG7>}@v9<>|UCx;|iLj=DmCRkbt#3?NQYIB2r%nwR@o@|fz?+=MOPU$&_8@9xG_E_HV zHQ~(sU^Z9{b9HP}^f6J+nCOD>Db{yqjRMmxo;tvxk(Q-i`l~^PJh|Q*=Abepda`)& zG0>Yz9+&){mZnwMo_)w^a)?)q7O%oS9_n<@AIfE0zoj6nJ=ns6#CL?Iu6((Hb6B3# ztm2R^&@crn?Gv-V7VdX=2;|JA@P zDytA-%s>w=~m&B z1NvLf;_ApxT>E(*xC(C+SuzKf7=juU!2u}1^L@WyRQO5||%DK)+GnxT$_U z5n!~#E-no!E2~wxLNUx5F4~Bangf&EDl1$3ehQ+Dqw11D4QS zAIdtxYK+7qWaokvhApEld*`1&$s7D^R$cy)yXlV{^A8s)EZ(W#97*q@Jn1V)NLwW= zR|>W4#pF9Ev`NY3kbB-3XvY) zcUk+wtqoMME;3yoZ6(Au&bH`4R_ZctTQDZqzD5qA56*U5 z4)p%q#m!oitAV|lqNj)h0V!2i3;X(+f`3KrUJbpgb-ENDXUyZ&SKN-1M?9&I8s9IK zy7Pqwhi&_Uc-_&gs3?ELy0v^G5-P$*c?02G=H&h{v4%NlFkhYbep=a27Q@=!9=Ge_ zZWaTYpWJ`jY;k%F-6W&-*wN_}q%KX3-ckb-oF24FOorWEB&N*%&S7nL_atQUvl60{ ztR~~vIPDmZ#((KwgtqE9gk99uUE%EtG6IbY#ScH{l!oDk;v~nt#mu>w*JHH?r+QGl zP>e_i_H`m1r=X=t_H~8?n^xo!y{xX&y=dNOAr6W>ScSz=cjvKv#NvMW~Be%jp z348tu=UP*uk^?(4N^CUN4fZ6hMZ|8-jH7-Iy!|f3=NzI~)u!&S>ey7vo1JW`6 zzFdu=)3{O;NV5BNWU6z14Ee1A=4h77#Y$oMrDd7i^LWGGPA8%=VbW=glwayRIBD+8 z{&Uge=%O~#$+ORvR%#Nay`szovVP28yrql2VYNtlJ(1Os7#a!OSl>S2)8cA4(8|A` z17Ia0eZ?<@RCuCw4POuVDab<%xRe^Q1#%V+KhE02c7nw(e%wgqprRSkoQBx$bKpPT zo$o`5&!xDR9&7|`J&s$y+u8T8e7AWoBd7Ad24jy=Q+$Oaku*CanN*hoY-O5?v|%57 z`u9s!ubz0GU=rXsBmam&h($7|hbgMRZ^1m!I?DztG@Aek#^m=(f%4fFO8;lW=48Yu zt=i?&?>T0-%qmByPJ4ComQ(vI8qs(=dFAV>$;)}PoAU=Pw~Zga)(txFb_o-%N=E$U zMU3kJLB5H+`W)E;kR!7v^jyg3AAzC{yM|wnhm`P0CdC1R{@WYMF4-;4^HhyiwAAh@ zGuZ`s62-6d&b3Fx6wAS>wQy_O%_^$6#aYkwW5TJRgRam)q1nMVAc6UG6?G3aFYI#U zA0(vq&3g4}&37se3Et1ijG+Ez=M2JC&HQ9;tTaXX;Dm#{=fa`4-aJc|Xy~g5z{}Zv z&4ff2D37R=?!vR-awFwD08fq-VPHl9KbCpH^AyP(C-0ZFY)a*G>7?DG)H5c$tT!OS zg_Tz1+=J>8WPMshgtTZM+PAsFZpuTgPH|%Qp(s-oThMVm$1of@YRbg$n0Qb5E8`*w zl&4R|Xv1@zl9W+(XtUR7(XdO33j;T$ptB>qc2(WHY?!2h+EZomx#97 zDZ(So(tE>*y#BuyjT9BMohq@J5%0Hs`(n?NQ<^ytL~B>oc&0tPMZcbUecXJP3Z}9J z4iec0S)g#g8JLK5UuTBlD_ARvI#|RzO2wabS-Mac# zWd+{#PC5r&wY95(9A<1e6fm4>V21;u-LMg;w@W~LfA5f(^SF@3IGZFcmGfuhT-gG6 zw5{XDts}!zN1gJ?RdB%`cuENNpijidV$x1FyXXu_2t6F6E?1@1czrb9`hH~km*1hy zQR5``+&uIf0c;uJ;~$vSS@B!H!>QZc9;vn91DA)Vj30X zBE(KiFx3Ci=P9iB3H+6n=;>)iogg_H5-Sn>8_!L5V&FQrmB8^DZ(r!NwgR2+wVoar zc5l8l80Ffod@k%u{&LtLDo@>cA2M|Fug5uaoD7P;Ik3-!mncVVe)Ut5kNJXvhJUGe z5ZluslOxRhvu7FY;iR^%9)wuppVCvY_{}skmBS_>)Td&n;G?(de~GqT3S4u%W!8^7Id-+LoAbX!ySayMLq`A*b!wC!P{a$tc`! zae;nISwo?7r`CextTQ_mPX`X?^#pa)33z7?zKeGl#y1T?U3KF=>*s1X^bmcCmqgg! zy^y1u)RqN4jk;sxqnh-ePL#+c)CFA`I^fd`8liRsP~u*}?el#YQggOGE!YEggY!c0 zGBzPm@yYx?u;e)hIqu*aW6l<)qDY4%7a}6Rg7?|R@yN+lyZc5MwObe=Kd8euAZ~>J zimBqbICxi^U48kp>D9gWn_|4U_tArM)DN1A-xRYqCDsk(dh+X>0vp_fPqwxW|B&Yg zO}l8rG$gK46$u&@+l%3qXiEXT(vASXw>{1Nmf?;TopsY^MW<*xZ_sDMCSP;^&*D#;&xYAM7|w`8#tr(*X?X?GD>E>=-L!ug5YU8d z+}Q6zyMxXR@YX9WdiCbt4xzUd`wwxh8!OViP5-i&f8(-RzZK4v&SdM6Z~yjXIN#dq zFnRmuM;$W50X#d5p?v(SEZJWlzL>Mnlb~N!DF2$=!|q3EZB$I`U^2*_<(>VML-h>f zobCNLcOmR}(7sF~8C)8wq*23@DKl=3%wv5+Spc3JMag%bqWK~)`h849!u5v!1R^Yq^BQ2 z7#BNjs_y&UjRE|{Pst(7u00m6x3DcWSK{;lUg?iW;28Lh*uNo_4mGK#V9uZF?IrUw}f&j zSDa=VD%Y8<`%#IgU%7v77F77ow1ONreSdS28JM{D-pV2H;Sx@l{5p4GP!~95ALl(J9WHQ#y(c@kt-yhUZZ-SjJBZHNQ?+{%BG#q9w~kdbg)&C z)H(l^{`@fym|l%+wfqMIlJ}ePoQ@Ki_|>sS)B=3%q7Ha;5_ji8$Kzoy`Z~Og82%mH z0rw{{;x#O6RI5SQ3Q;gG1@JM_;M)w7h31-AMN^h^Eu{=2b*sK^4dwVlw_ke176RIY z(JAnE9v0X#2P*psLKKGffn7~Kk2XZ9P=?#(nM&;BncnBVLT^XDMGt>(t4OQL7J8RW zdiGZ3&LOC^VmXHnV%G;8J{(+uSg>mwwS;@4TN^BoS@6gf;{}yNJ1qZ~n|-)=h;>rM zyC8|Bo2BF2ji1)1em{nZyjh0oGfa{*jL7KwrEgk^y>pq^*R6TgIwsc6W?a5(zQrBq zv4cBb6og%#VsT;h*Zn&r%HCzlpych^5y>tNV&(!7#nRcpybq^9q58Cq)APk9&ZP4k z5(-z<%_g>cYTJ&^Trn^xhJDHbLrNu~Z$8Y=G9&cr!Qc48r-P%XE#M3K73=pZa`?Tp z!1LE5fn#=$$sZzgWU~2ylCB(-IOaenMn%rI6bi4q=T@-G^rm*OZ~;$L$NK`c%u71m z%p@ERmzOd*R@GO|#z1EQB^I8Sk!N*2Tf;|m1)Y=$ zZHAw|d-mEZ*-yMb$n7~C*ZC|5igDK!WlLrmfQYL0Jesn*zKQ_6VnH{~zXhbeDM zkI7RMG3wHYOypFodj;uKV1B8$lGYbr)C&}`1nmS+!+J|8*fa?HdO z`yzDML_SraW!>X}OLU6m#&7oOZpHb*&HlE&%HD{Y^%!fOkD?_mjqA-W8|nbU({a@M z+HrUOsR~ONOKxzc4@3Qcq3o|&QO3XSU0MrcwJIwe%5q(!pqMlGk5>I;p=|Mth^X;; z(#@pkJ0mWjZiDegSDF<*1ZC4w|A((s&AH=E92Q&tu|Vn^-M#Mz59*i4WqW-1I{BgN ztU%0-QdS`z+50WcJC*L}5(1wk8<%ebZ$cq)Onm<+2LcDXZ~ zRlFC=5hJz}r<^X-{QD({{8oiV-wG%_{V}K*5+kKT?i5mA@m#>~JHaRE+)VM2W+-yt z2F7_Ilu}=VZD5&Pjc}T~SU)O%BW2xC+vIT9urhk^L&xKFAEVL*VHj4OIer+tm3+I? zL_nDu1dW>wokN7$N4F}mFT@G>hSvY$8g5%8*nG?^7uTOBk0}v3smON-zZ5r9Wxg`m zgWrNotR%%wlM`hcJowX3c3f-q^uMThEk7G5xw%tlcAE6F)w1X3s)5;l+wBmiXv~z@ z$N7-f>ti`*aO}zs`pW9R2wwG7T=f1UgVNni@+IHYI{hRR-XvA3;Sme|aoZ>K%cX>l78>51MDbb(iIog(E;JsJpXm`vL?u9xI?u2LQ8C* zzvF+aZ)({y3QFQ|_$OX{@(~`-nVvd*?9Lb$^7@T*1JEQmDyUz?(KH;=I}_9Sa#O3~ z9{r#d|J@VH{l3G`Gvt>1$U*EVnb&#-(ZSM-*K10{Z|_3w8Rq{-ocntQ(;L;G8wVF$e6RMsDUbLbhA zTu;y_p_h+5Sn>O!K7Hn-78eY&X)E&3z2B`NKIY{7>$1gif;zuI85DIE2QUO0d#(RH zG$p}ep}$P=9}}BARBQIXC=Qurx10nu@elnz)iY+;{ItXZW14==?#W!>9M*b^&`d5- ztJup*Xa$UP%PD=H?me&EZ==JSXcM8D>lJ4Ysu_38&Qh41IevY3?UlW$*%Ybb+1nOF zqI^fQSk3$V06K0L9Fce$#{bp)sb1nF`)F35$0cS|g!8aF?n~Xp>QvHjUj01r>prWu zO}}RBtxxp!FkE>XAdF8+Tao9P-AJN%GSGk4piWj$6{8|f% zy+Bx3;iNI15t!#g+0FHNNx`fHr8%r*l7;el1Row~&m2ae8PYvdT@2sqK8=~Z+C6PL zHSiH(29i$S=&)o{Y(x+LBWzOR|MG$eB@1LY90bPZ?m9a=%%PN8%wCpLQ2xDRiP!b* z`tzq7>Yf5{VDg@{TgWOJ%%9hR%wHa^YYj#OVaggv87*KusA!E2=O!cmupPWS>L zdbC%`C;u29$_++K1dHN;3&!uSo1}fe9JEgY(=(P6zfxn)tfzCW;L*@-x>nOb4DlV5FDEAF~e8zUpLAtr`Q4oAzY(0;2< z#?2M>kHbz$nKuYb8;B^>*yL0Fl8}iHG&8M$TVP1}cs7}Fqt*J!n~vH2GQNmRy## zmUS*-!km4sLAxAb-5&#h0S+EH`weC1!2}H$MR8-~>1ox#d7BL?463p;QrpTq_pkbi zVRu7W#~Hpfy}D&xKdYU%u)KOTytUj>s#83cS}FNzss!<(r3#mf@iY3D9CB@D#XS?F|I*k%fF~e zS~TwJ;XNzX!OH7Uc-Kc>hd)FwZu-4a(>A}lEK0sCz^cpcdqA1+Nsa1E`Pc`wV^zDe zTt247*(wUWB|`k3>Fa9XyjJlV^iKqKSx9ygH_-(3lhUc6t*` zhwkvg@s`Pp@lzd?7?&!<)-Z3Zb0%a!aksCEpajVr?}1ddSt4 z+DMqhBKCA*Hlwe{NheCOvapIs^1uLH97*EZD4}w-lGwAw<{z%byj8gAo z_qeqI5md`0mRC-z)h{Jv-QVyRulzbb%X3wWBPp!yRt0v$85SK1eZtUbZ**Yd?fOf@ znwbIh-EbN4v7+%VBW$i19c!gmnum)8Vh)rur^7T3ax#-C}2(4KwOi4Exe4 z|Iu5wGjiFN*l*@#WivT7S%N8{naS3Aaf1kB-Yx7BXh7afp3j^oBp2v7ddv0mD&XSplWVMY_wbdpYmdjmsk1{{;uh(Xg@uQ!(ef?4vJW9zZkIe+ z5?G?5Bqc3wWAA`@cH9}&D^9c5&&PuQc9epEy7S*FZHbR*3}NxGGXlH=j_E$oL6FDV z;P%3Z*IX)x>2~>@6hHUd1lpdTiCnyoKzMpg7dbAAe@}q>s|`o5 z|HmvZG#etp@fx1h2$)$sxu-3!t7j-8hN zP6&5xI2_aSVZko0U?mPssgiqHg=1^y0(g#j?k5>Tgx50tV4%ugvU1FSUdQc-7!nlC zz>=Gzc7PIX`7b^>`PR$|sL;_VE_s5F6wfP8(Yl)Y=ze5Wp^E=fzaB+gx@R|w}xQR?7 zk6vDm&R64KPPA^a4@yP0{D?tr@ro%^TxgbaGXY99 z4q%i-mZFg0;ubn;(^CX0XC5zag(RJ;ju>Rm3B=gUW;d|SU380Uw29Zw9l5saS(Yjz zWhi@SmZyFDq?pD$nn-_z_`Be8DKaHcF2+S`nCFKhS#stUN|~~uOj%O>$A4Xpq-Yq$ ztOQ=g8!Ic9L+uPASE}I)>2l?eyPw95z=Ltr3+XTu~y;=}{o{WZ+|pjo8qSvAM7*Y3c= z9^a7YMiG*q@Kk=XTvVIUBwUoZ*6GPvnFWGfm zs&<$8M5y7@@>Wn`Pj{BwGR{vU#;$;N6OI7S?O>5hy;z%>Wm{SdbI}D)nHoYyl4)@?(1=Ju6-%BF${nc8+ly~qU;nBzU%di zzrwil5)>fI7eexb{idfFi^jKl;KyOCr^ySm0f&HX(*L-rk&%%-_yI?qZj)>$smR6o z5s}(dU$(r|O7=3`b}+KiZ@?^Rq2&J8HtBZz;h%hp`0HHeh$?H6Pq@C0(;`Mq4QuZZ zC?(Y6F4ML+CRV;!TX&JS>-JoJTkr`s%l%Zo_ijjpPgak0apbi6h*)6e1TeiiQCmE9 zbaMn>TF$9oW8U#_N#EYyyOxUCU8;`dSScvdtJ@6#Vp@pRpe~2BsjG381 zB?fE0&Y8KKQ24xq(c|$!=0ULyP(dQ#bndYX4g&FB<@otRH)=%QX~Gks%o_qEOz9U} zhmp4?9LH~79@}i5z6fMHlo>(StdL;Fb$a1B`xi@FtU8uCIn>344(IC z8@@r%B2JW}B8jVnYXb+B-Vnr}tALO1{6AN`!y`jyCLma&4i{k0zXnNVd&&iVH2!u` zcLce0uHsxv0SGF!RTr8WnZjTRH@3leG(PdN*Iu)Vr!8=a5KqLO;;s<7ilr6w>o*!c z?18Ed9lpWu%@+J4oXRor-vIXBKwVBY4)$NgK9sc&jFO{pKZyho!AQKB2c4gtDI0k# zr@K7!^>PVJb_Fl;0|aGCazvmTtQ7ncC_` zJf|BNN0q`q_ejocdJHjq3XUx<*P9h`sd>R+yxPZV45#tiPN<)v%egfMpb^NJFO+!s zvp*Z|aDTSC=lNg(wmCqWU1`6apDfFUd>{BFmCNUZ*7zIY^ZaS=>ABl#tnXI}{umcp zW5RLI0B5mYdXy;vM!c9-t^qbzFQyU}?hV0fh^x)bpkO0CE-FO8yYpT zV3)58C^WVogbi>na^~>z_39 z@kIeTmEcaTx>`M+ZbSwU{sRtcWM^knHM?9CyKH{&ws2|r)eLI^)x+amB*4ml)G3_j zsc zWGc&TQDQH?g%cI%(YrU~a4}y1f(A}_@z?QkFC$%<@iMialdiP5Xrf$vf{}|S0P*dk zFDN3>Q~!uC2Y>3#I}vkt6Zfsb5y;NW#e-rv?yyE9>01JQl9S6+#J4G+MckGuWuB3@ zeQ7NrhbtF7$dMJv;VXPo;_hzLM@k1MvdlYNpSvD-{-`#{&p_EnGD?MslPp?UEjWqW z$ND$4;xW`BZ}eb%Dj*n>wHr@7nH4%Ap1~@b15~} zG6uxH9M=U7Hjc^nqJfy~X;gxte<5CN)zMjK03UjV zf=5P*c7zZ_9uZ-qCx6C{JxQIKpRnLFwz#ksk011ye^Em?-N%^G&7hwfJDIEU?1X(> zYJ0##{H{^0dlry#q&U391OQsVx8-f8(?ykD4QEsRa04z)$aja#BRM4+Lp@wN!1Jd% zy(xA!4pI9xU-*Fwjp4?91Lr}>sK^53ab-^rF&a_f3t?+}EGM5MTg41cxUPo-EQV&1+bpXd7?kkKnrqjm;VqbI7ORP~^s_wB zz7EnzlCWlvhw0AO91+TOrXDq!B5&)hnjD_~c{<_zAFJcfgdB$iUnI2}M>uh0YdWlB z7XAj0tvQI!Y~zAA+}qP?|%Y6C9uUV3>}^L>XyjpXVFu;qlMax&NHX zK0?rh23Igw9V;~bs41Js{~g$?wX^eT)r8|2E}8G!grlnNF%}a?*PWbkbb5_Z_argm zK`&2>C62m55kBmVerUMa%=%-~+3*u6I*l{doV0}YGY<|?mV55pu(FOzjDv_E6o^A| zs^ca#v2o0Azcbq>hl}K9g@(F@p2KP6Yf-3?c^JGtpw-Nl8Y{D-5Lt5hp6+e|kr-Fb z^=`68pPJ|YjN=R?d?pO!g(`oxtM8F6yZt5b4IW~3##eC|hy%xZ3FL%?MEU;8VKY%j z%3O+SJW8L(-`=*tgGmh78^j^2|75g0=_AU%=G9ssij56{Bg&qsgES!U0$ghQ5h!B! z1*p5&_tNgt!tplvyHQPnv7w<*A?JQ$SSAj95j+M5-)qz;o5K@Y+b(cGhX{RD;pP$1 zR__rFaR?R8fTBm!r4E(;M^vEvDmPl>_)pKCt;~R#_KXXMpx>az7Gb}UwomWtfdsnv zT6yhhstp=pOUQ&j=3VXq-tc_NGWf(&h(8aftFbkl4%L}ZkyI)Av2=5 ze2+_WiQR8*&Qho>@!Nw=ul@NeTo#@^KFqm)6M&f{qk@LJlFpp42j98Wsl(JYuTvl@ z$j2a#>~XPjT~_!YgwA!?E>hu=#_+hNC`%S)!hKbjomzSYIKuaB;l;+Op`TTfV?geZ^mb&`ht`_p)qUzX-A{S zf(lx`ZzAw9+~7L<_)&^yK&BjW>EU zJcDh{X}^>T6anr8pT9Y$7}zSbjn+&4Ch|p`iRD*bLBR)~6&n*K&OVm+xjK2)v7C(| zHsLF$7))b4qv+6}85-*UX^(**aI?A3;hdbcO*doBuN-!|yrui={p_u`j#d?HSjU-Q z&B9?3WHr}r@pT?AptD}t-B{lJ*m6_u;~KNs_W2T^o&6n#JOwr^96Ov0By3I!nlIEi zwPTUScj-3Ig#iU!&s#Iiw?tU&$!Jd1B9woikk>8q^gX z4w%1ER6bp__-In3nCZFh{WEpfDm`0k&UxJQ-<6AE^8f$J@{YOlXP=)2^aO*atDnm{r-UW|bln!P diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 67bc6f3ab..85b4e9446 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -1,17 +1,16 @@ -file(GLOB_RECURSE RESOURCES ../Resource/*) -foreach(R ${RESOURCES}) - string(REGEX REPLACE ".*Resource/" "" FILENAME ${R}) - list(APPEND FINAL_RESOURCES ${R}->../Resource/${FILENAME}) -endforeach() +set(CMAKE_PREFIX_PATH ${QT_LIB_PREFIX}) +find_package( + Qt6 ${QT_VERSION} + COMPONENTS Core Gui Widgets + REQUIRED +) + +qt_standard_project_setup() file(GLOB_RECURSE SOURCES Src/*.cpp) -AddExecutable( - NAME Editor - SRC ${SOURCES} - INC Include - LIB Qt Core RHI Runtime - RES ${FINAL_RESOURCES} -) +qt_add_executable(Editor ${SOURCES}) +target_include_directories(Editor PRIVATE Include) +target_link_libraries(Editor PRIVATE Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets) set_target_properties( Editor PROPERTIES diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 66928d5a6..e9396450e 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -251,26 +251,22 @@ Add3rdHeaderOnlyPackage( ) # Qt6 -Find3rdPackage( +set(QT_VERSION "6.5.2" CACHE STRING "" FORCE) +Setup3rdPackage( NAME Qt - PACKAGE Qt6 - VERSION 6.5.2 + VERSION ${QT_VERSION} HASH Windows e2a573a53b6de88c0ce768868bd5a8258d432ad71c45a407afa55243b051668f Darwin 2fadcb1f07e5f11d4345e7d5631f35f8f4a8033c35901fb20a22c2feb7486e57 PREFIX Windows $/6.5.2/msvc2019_64 Darwin $/6.5.2/macos - COMPONENTS Core Gui Widgets - LIB Qt::Core Qt::Gui Qt::Widgets - RUNTIME_DEP - Windows - $/6.5.2/msvc2019_64/plugins/platforms/qwindows$,d,>.dll->platforms/qwindows$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Core$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Gui$,d,>.dll - $/6.5.2/msvc2019_64/bin/Qt6Widgets$,d,>.dll ) -set(Qt6Core_VERSION_MAJOR 6 CACHE STRING "" FORCE) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/msvc2019_64 CACHE PATH "" FORCE) +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(QT_LIB_PREFIX ${Qt_SOURCE_DIR}/${QT_VERSION}/macos CACHE PATH "" FORCE) +endif () # rapidjson Add3rdHeaderOnlyPackage( From 83390c32689cf1c8b01cfe27f61c209a40c22eed Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Tue, 31 Dec 2024 18:33:51 +0800 Subject: [PATCH 11/12] feat: support qt quick --- Editor/Source/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 85b4e9446..7184321f6 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -1,16 +1,17 @@ set(CMAKE_PREFIX_PATH ${QT_LIB_PREFIX}) find_package( Qt6 ${QT_VERSION} - COMPONENTS Core Gui Widgets + COMPONENTS Core Gui Widgets Quick REQUIRED ) qt_standard_project_setup() +qt_policy(SET QTP0001 NEW) file(GLOB_RECURSE SOURCES Src/*.cpp) qt_add_executable(Editor ${SOURCES}) target_include_directories(Editor PRIVATE Include) -target_link_libraries(Editor PRIVATE Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets) +target_link_libraries(Editor PRIVATE Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick) set_target_properties( Editor PROPERTIES @@ -18,3 +19,12 @@ set_target_properties( AUTORCC ON AUTOUIC ON ) + +file(GLOB_RECURSE QML_SOURCES QML/*.qml) +file(GLOB_RECURSE RESOURCES Resource/*) +qt_add_qml_module( + Editor + URI exp.editor + QML_FILES ${QML_SOURCES} + RESOURCES ${RESOURCES} +) From 3c8385371ea89d4a3963263ec36bddfda4c7079b Mon Sep 17 00:00:00 2001 From: FlyAntNotDown <461425614@qq.com> Date: Tue, 31 Dec 2024 18:55:23 +0800 Subject: [PATCH 12/12] feat: project launcher update --- Editor/QML/launcher.qml | 5 ++ Editor/Source/CMakeLists.txt | 21 +++---- Editor/Source/Include/Editor/QmlHotReload.h | 28 +++++++++ Editor/Source/Include/Editor/Resource.h | 30 --------- Editor/Source/Include/Editor/Theme.h | 37 ----------- .../Source/Include/Editor/Widget/Launcher.h | 11 +--- .../Source/Include/Editor/Widget/QmlWidget.h | 24 ++++++++ Editor/Source/Src/Main.cpp | 5 ++ Editor/Source/Src/QmlHotReload.cpp | 37 +++++++++++ Editor/Source/Src/Resource.cpp | 40 ------------ Editor/Source/Src/Theme.cpp | 61 ------------------- Editor/Source/Src/Widget/Launcher.cpp | 42 +------------ Editor/Source/Src/Widget/QmlWidget.cpp | 42 +++++++++++++ 13 files changed, 154 insertions(+), 229 deletions(-) create mode 100644 Editor/QML/launcher.qml create mode 100644 Editor/Source/Include/Editor/QmlHotReload.h delete mode 100644 Editor/Source/Include/Editor/Resource.h delete mode 100644 Editor/Source/Include/Editor/Theme.h create mode 100644 Editor/Source/Include/Editor/Widget/QmlWidget.h create mode 100644 Editor/Source/Src/QmlHotReload.cpp delete mode 100644 Editor/Source/Src/Resource.cpp delete mode 100644 Editor/Source/Src/Theme.cpp create mode 100644 Editor/Source/Src/Widget/QmlWidget.cpp diff --git a/Editor/QML/launcher.qml b/Editor/QML/launcher.qml new file mode 100644 index 000000000..f8c63e1ff --- /dev/null +++ b/Editor/QML/launcher.qml @@ -0,0 +1,5 @@ +import QtQuick + +Rectangle { + color: 'red' +} diff --git a/Editor/Source/CMakeLists.txt b/Editor/Source/CMakeLists.txt index 7184321f6..3ad567ab3 100644 --- a/Editor/Source/CMakeLists.txt +++ b/Editor/Source/CMakeLists.txt @@ -5,26 +5,25 @@ find_package( REQUIRED ) -qt_standard_project_setup() -qt_policy(SET QTP0001 NEW) +qt_standard_project_setup(REQUIRES ${QT_VERSION}) file(GLOB_RECURSE SOURCES Src/*.cpp) qt_add_executable(Editor ${SOURCES}) target_include_directories(Editor PRIVATE Include) target_link_libraries(Editor PRIVATE Core RHI Runtime Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Quick) -set_target_properties( - Editor PROPERTIES - AUTOMOC ON - AUTORCC ON - AUTOUIC ON -) +file(GLOB_RECURSE QML_SOURCES ../QML/*.qml) +file(GLOB_RECURSE RESOURCES ../Resource/*) + +list(APPEND RESOURCES_PENDING_SET_ALIAS ${QML_SOURCES} ${RESOURCES}) +foreach (RESOURCE ${RESOURCES_PENDING_SET_ALIAS}) + get_filename_component(FILENAME ${RESOURCE} NAME) + set_source_files_properties(${RESOURCE} PROPERTIES QT_RESOURCE_ALIAS ${FILENAME}) +endforeach () -file(GLOB_RECURSE QML_SOURCES QML/*.qml) -file(GLOB_RECURSE RESOURCES Resource/*) qt_add_qml_module( Editor - URI exp.editor + URI editor QML_FILES ${QML_SOURCES} RESOURCES ${RESOURCES} ) diff --git a/Editor/Source/Include/Editor/QmlHotReload.h b/Editor/Source/Include/Editor/QmlHotReload.h new file mode 100644 index 000000000..57b52e435 --- /dev/null +++ b/Editor/Source/Include/Editor/QmlHotReload.h @@ -0,0 +1,28 @@ +// +// Created by Kindem on 2024/12/31. +// + +#pragma once + +#include + +#include + +namespace Editor { + class QmlHotReloadEngine { + public: + static QmlHotReloadEngine& Get(); + + ~QmlHotReloadEngine(); + + void Start(); + void Stop(); + void Register(QQuickView* inView); + void Unregister(QQuickView* inView); + + private: + QmlHotReloadEngine(); + + std::unordered_set liveQuickViews; + }; +} diff --git a/Editor/Source/Include/Editor/Resource.h b/Editor/Source/Include/Editor/Resource.h deleted file mode 100644 index 151ef543d..000000000 --- a/Editor/Source/Include/Editor/Resource.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#pragma once - -#include - -#include - -namespace Editor { - class Resource { - public: - explicit Resource(std::string inFile); - - std::filesystem::path Path() const; - std::string String() const; - operator std::filesystem::path() const; // NOLINT - operator std::string() const; // NOLINT - operator QString() const; // NOLINT - - private: - std::string file; - }; - - class StaticResources { - public: - static Resource picLogo; - }; -} diff --git a/Editor/Source/Include/Editor/Theme.h b/Editor/Source/Include/Editor/Theme.h deleted file mode 100644 index ebdbc63c6..000000000 --- a/Editor/Source/Include/Editor/Theme.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#pragma once - -#include - -namespace Editor { - class Theme { - public: - Theme(); - - Theme& SetColorPrimary(const QColor& color); - Theme& SetColorSecondary(const QColor& color); - Theme& SetColorBackground(const QColor& color); - QColor GetColorPrimary() const; - QColor GetColorSecondary() const; - QColor GetColorBackground() const; - - private: - QColor colorPrimary; - QColor colorSecondary; - QColor colorBackground; - }; - - extern Theme defaultTheme; - - class ThemeSwitcher { - public: - static void Set(const Theme& inTheme); - static const Theme& Current(); - - private: - static Theme current; - }; -} diff --git a/Editor/Source/Include/Editor/Widget/Launcher.h b/Editor/Source/Include/Editor/Widget/Launcher.h index 465ffca87..fc8335d05 100644 --- a/Editor/Source/Include/Editor/Widget/Launcher.h +++ b/Editor/Source/Include/Editor/Widget/Launcher.h @@ -4,20 +4,13 @@ #pragma once -#include -#include +#include namespace Editor { - class Launcher final : public QWidget { + class Launcher final : public QmlWidget { Q_OBJECT public: Launcher(); - - void SetWindowProperties(); - void CreateMainRow(); - void CreateMenuCol() const; - - QHBoxLayout* mainRow; }; } diff --git a/Editor/Source/Include/Editor/Widget/QmlWidget.h b/Editor/Source/Include/Editor/Widget/QmlWidget.h new file mode 100644 index 000000000..9fed2f42b --- /dev/null +++ b/Editor/Source/Include/Editor/Widget/QmlWidget.h @@ -0,0 +1,24 @@ +// +// Created by Kindem on 2024/12/31. +// + +#pragma once + +#include +#include + +namespace Editor { + class QmlWidget : public QWidget { + Q_OBJECT + + public: + explicit QmlWidget(const std::string& qmlFileName, QWidget* parent = nullptr); + + QQuickView* GetQuickView(); + const QUrl& GetQmlUrl() const; + + private: + QUrl url; + QQuickView* quickView; + }; +} diff --git a/Editor/Source/Src/Main.cpp b/Editor/Source/Src/Main.cpp index b6415ec09..038ea78f9 100644 --- a/Editor/Source/Src/Main.cpp +++ b/Editor/Source/Src/Main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include int main(int argc, char* argv[]) @@ -19,7 +20,11 @@ int main(int argc, char* argv[]) // TODO editor main } mainWindow->show(); + + auto& qmlHotReloadEngine = Editor::QmlHotReloadEngine::Get(); + qmlHotReloadEngine.Start(); const int execRes = QApplication::exec(); + qmlHotReloadEngine.Stop(); mainWindow = nullptr; Editor::Core::Get().Cleanup(); diff --git a/Editor/Source/Src/QmlHotReload.cpp b/Editor/Source/Src/QmlHotReload.cpp new file mode 100644 index 000000000..170c37cdb --- /dev/null +++ b/Editor/Source/Src/QmlHotReload.cpp @@ -0,0 +1,37 @@ +// +// Created by Kindem on 2024/12/31. +// + +#include + +namespace Editor { + QmlHotReloadEngine& QmlHotReloadEngine::Get() + { + static QmlHotReloadEngine engine; + return engine; + } + + QmlHotReloadEngine::QmlHotReloadEngine() = default; + + QmlHotReloadEngine::~QmlHotReloadEngine() = default; + + void QmlHotReloadEngine::Start() + { + // TODO + } + + void QmlHotReloadEngine::Stop() + { + // TODO + } + + void QmlHotReloadEngine::Register(QQuickView* inView) + { + liveQuickViews.emplace(inView); + } + + void QmlHotReloadEngine::Unregister(QQuickView* inView) + { + liveQuickViews.erase(inView); + } +} // namespace Editor diff --git a/Editor/Source/Src/Resource.cpp b/Editor/Source/Src/Resource.cpp deleted file mode 100644 index 2f38d5375..000000000 --- a/Editor/Source/Src/Resource.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#include -#include - -namespace Editor { - Resource::Resource(std::string inFile) - : file(std::move(inFile)) - { - } - - std::filesystem::path Resource::Path() const - { - return ::Core::Paths::EngineRes() / file; - } - - std::string Resource::String() const - { - return Path().string(); - } - - Resource::operator std::filesystem::path() const - { - return Path(); - } - - Resource::operator std::string() const - { - return String(); - } - - Resource::operator QString() const - { - return QString::fromStdString(String()); - } - - Resource StaticResources::picLogo = Resource("logo.png"); -} diff --git a/Editor/Source/Src/Theme.cpp b/Editor/Source/Src/Theme.cpp deleted file mode 100644 index 68c5d3362..000000000 --- a/Editor/Source/Src/Theme.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Created by johnk on 2024/8/23. -// - -#include - -namespace Editor { - Theme::Theme() - : colorPrimary() - , colorSecondary() - , colorBackground(0x24, 0x29, 0x2f) - { - } - - Theme& Theme::SetColorPrimary(const QColor& color) - { - colorPrimary = color; - return *this; - } - - Theme& Theme::SetColorSecondary(const QColor& color) - { - colorSecondary = color; - return *this; - } - - Theme& Theme::SetColorBackground(const QColor& color) - { - colorBackground = color; - return *this; - } - - QColor Theme::GetColorPrimary() const - { - return colorPrimary; - } - - QColor Theme::GetColorSecondary() const - { - return colorSecondary; - } - - QColor Theme::GetColorBackground() const - { - return colorBackground; - } - - Theme defaultTheme = Theme(); // NOLINT - - void ThemeSwitcher::Set(const Theme& inTheme) - { - current = inTheme; - } - - const Theme& ThemeSwitcher::Current() - { - return current; - } - - Theme ThemeSwitcher::current = defaultTheme; -} diff --git a/Editor/Source/Src/Widget/Launcher.cpp b/Editor/Source/Src/Widget/Launcher.cpp index fdb097212..8dab65c08 100644 --- a/Editor/Source/Src/Widget/Launcher.cpp +++ b/Editor/Source/Src/Widget/Launcher.cpp @@ -2,52 +2,12 @@ // Created by johnk on 2024/6/23. // -#include -#include -#include - #include #include // NOLINT -#include -#include namespace Editor { Launcher::Launcher() + : QmlWidget("launcher.qml") { - SetWindowProperties(); - CreateMainRow(); - CreateMenuCol(); - } - - void Launcher::SetWindowProperties() - { - setFixedSize(QSize(800, 600)); - setWindowTitle(tr("Launcher")); - setWindowIcon(QIcon(StaticResources::picLogo)); - - QPalette pal(palette()); - pal.setColor(backgroundRole(), ThemeSwitcher::Current().GetColorBackground()); - setPalette(pal); - } - - void Launcher::CreateMainRow() - { - mainRow = new QHBoxLayout(); - mainRow->setContentsMargins(QMargins(50, 50, 50, 50)); - setLayout(mainRow); - } - - void Launcher::CreateMenuCol() const - { - auto* menuCol = new QVBoxLayout(); - mainRow->addLayout(menuCol); - - auto* logoAndVersionRow = new QHBoxLayout(); - menuCol->addLayout(logoAndVersionRow); - - auto* logoLabel = new QLabel(); - logoLabel->setPixmap(QPixmap(StaticResources::picLogo).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - logoLabel->setAlignment(Qt::AlignVCenter); - logoAndVersionRow->addWidget(logoLabel); } } diff --git a/Editor/Source/Src/Widget/QmlWidget.cpp b/Editor/Source/Src/Widget/QmlWidget.cpp new file mode 100644 index 000000000..9df364566 --- /dev/null +++ b/Editor/Source/Src/Widget/QmlWidget.cpp @@ -0,0 +1,42 @@ +// +// Created by Kindem on 2024/12/31. +// + +#include + +#include +#include // NOLINT + +namespace Editor { + QmlWidget::QmlWidget(const std::string& qmlFileName, QWidget* parent) + : QWidget(parent) + , url(QUrl(QString(std::format("qrc:/qt/qml/editor/{}", qmlFileName).c_str()))) + , quickView(new QQuickView) + { + quickView->setResizeMode(QQuickView::SizeRootObjectToView); + quickView->setSource(url); + quickView->show(); + + QWidget* quickViewContainer = createWindowContainer(quickView); + quickViewContainer->setMinimumSize(quickView->size()); + quickViewContainer->setFocusPolicy(Qt::TabFocus); + + QVBoxLayout* layout = new QVBoxLayout(); // NOLINT + setLayout(layout); + + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(quickViewContainer); + + // TODO support hot reload + } + + QQuickView* QmlWidget::GetQuickView() // NOLINT + { + return quickView; + } + + const QUrl& QmlWidget::GetQmlUrl() const + { + return url; + } +} // namespace Editor