1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "dotfield/ecs/systems/dotfield_system.h"
17 
18 #include <PropertyTools/property_api_impl.h>
19 #include <PropertyTools/property_api_impl.inl>
20 #include <PropertyTools/property_data.h>
21 #include <PropertyTools/property_macros.h>
22 #include <cmath>
23 #include <random>
24 
25 #include <3d/ecs/components/transform_component.h>
26 #include <3d/ecs/components/world_matrix_component.h>
27 #include <base/containers/fixed_string.h>
28 #include <base/containers/unordered_map.h>
29 #include <base/math/matrix_util.h>
30 #include <base/math/quaternion_util.h>
31 #include <base/math/vector_util.h>
32 #include <core/ecs/intf_component_manager.h>
33 #include <core/ecs/intf_ecs.h>
34 #include <core/implementation_uids.h>
35 #include <core/intf_engine.h>
36 #include <core/plugin/intf_class_factory.h>
37 #include <core/property/intf_property_api.h>
38 #include <core/property/intf_property_handle.h>
39 #include <render/datastore/intf_render_data_store_manager.h>
40 #include <render/implementation_uids.h>
41 
42 #include "dotfield/ecs/components/dotfield_component.h"
43 #include "render/render_data_store_default_dotfield.h"
44 
45 namespace {
46 #include "app/shaders/common/dotfield_struct_common.h"
47 } // namespace
48 
49 using namespace BASE_NS;
50 using namespace CORE_NS;
51 using namespace RENDER_NS;
52 using namespace CORE3D_NS;
53 using namespace Dotfield;
54 namespace {
55 
56 class DotfieldSystem final : public IDotfieldSystem, private IEcs::ComponentListener {
57 public:
58     DotfieldSystem(IEcs& aECS);
59     ~DotfieldSystem();
60 
61     // ISystem
62     string_view GetName() const override;
63     Uid GetUid() const override;
64 
65     IPropertyHandle* GetProperties() override;
66     const IPropertyHandle* GetProperties() const override;
67     void SetProperties(const IPropertyHandle&) override;
68 
69     bool IsActive() const override;
70     void SetActive(bool state) override;
71 
72     void Initialize() override;
73     void Uninitialize() override;
74     bool Update(bool frameRenderingQueued, uint64_t time, uint64_t delta) override;
75 
76     const IEcs& GetECS() const override;
77 
78     void OnComponentEvent(
79         EventType type, const IComponentManager& componentManager, array_view<const Entity> entities) override;
80 
81 private:
82     struct PropertyData {
83         float speed { 1.f };
84     };
85 
86     BEGIN_PROPERTY(PropertyData, ComponentMetadata)
87         DECL_PROPERTY2(PropertyData, speed, "Simulation speed", 0)
88     END_PROPERTY();
89 
90     bool active_ { true };
91     IEcs& ecs_;
92     IRenderDataStoreManager& renderDataStoreManager_;
93     IWorldMatrixComponentManager& worldMatrixManager_;
94     IDotfieldComponentManager& dotfieldManager_;
95 
96     PropertyData props_ { 1.f };
97 
98     PropertyApiImpl<PropertyData> propertyApi_ = PropertyApiImpl<PropertyData>(&props_, ComponentMetadata);
99 };
100 
DotfieldSystem(IEcs& ecs)101 DotfieldSystem::DotfieldSystem(IEcs& ecs)
102     : ecs_(ecs), renderDataStoreManager_(GetInstance<IRenderContext>(
103                      *ecs.GetClassFactory().GetInterface<IClassRegister>(), UID_RENDER_CONTEXT)
104                                              ->GetRenderDataStoreManager()),
105       worldMatrixManager_(*GetManager<IWorldMatrixComponentManager>(ecs)),
106       dotfieldManager_(*GetManager<IDotfieldComponentManager>(ecs))
107 {
108     ecs.AddListener(dotfieldManager_, *this);
109 }
110 
~DotfieldSystem()111 DotfieldSystem ::~DotfieldSystem()
112 {
113     ecs_.RemoveListener(dotfieldManager_, *this);
114 }
115 
SetActive(bool state)116 void DotfieldSystem::SetActive(bool state)
117 {
118     active_ = state;
119 }
120 
IsActive() const121 bool DotfieldSystem::IsActive() const
122 {
123     return active_;
124 }
125 
GetName() const126 string_view DotfieldSystem::GetName() const
127 {
128     return Dotfield::GetName(this);
129 }
130 
GetUid() const131 Uid DotfieldSystem::GetUid() const
132 {
133     return UID;
134 }
135 
GetProperties()136 IPropertyHandle* DotfieldSystem::GetProperties()
137 {
138     return propertyApi_.GetData();
139 }
140 
GetProperties() const141 const IPropertyHandle* DotfieldSystem::GetProperties() const
142 {
143     return propertyApi_.GetData();
144 }
145 
SetProperties(const IPropertyHandle& dataHandle)146 void DotfieldSystem::SetProperties(const IPropertyHandle& dataHandle)
147 {
148     if (dataHandle.Owner() != &propertyApi_) {
149         return;
150     }
151     if (auto data = ScopedHandle<const PropertyData>(&dataHandle); data) {
152         props_ = *data;
153     }
154 }
155 
GetECS() const156 const IEcs& DotfieldSystem::GetECS() const
157 {
158     return ecs_;
159 }
160 
Initialize()161 void DotfieldSystem::Initialize() {}
162 
Uninitialize()163 void DotfieldSystem::Uninitialize() {}
164 
Update(bool frameRenderingQueued, uint64_t time, uint64_t delta)165 bool DotfieldSystem::Update(bool frameRenderingQueued, uint64_t time, uint64_t delta)
166 {
167     if (!active_) {
168         return false;
169     }
170 
171     RenderDataStoreDefaultDotfield* dsDefaultDotfield = static_cast<RenderDataStoreDefaultDotfield*>(
172         renderDataStoreManager_.GetRenderDataStore("RenderDataStoreDefaultDotfield"));
173     if (dsDefaultDotfield) {
174         const auto timeStep = delta * 0.000001f * props_.speed;
175         dsDefaultDotfield->SetTimeStep(timeStep);
176         dsDefaultDotfield->SetTime(time * 0.000001f);
177 
178         array_view<RenderDataDefaultDotfield::DotfieldPrimitive> dotfieldPrimitives =
179             dsDefaultDotfield->GetDotfieldPrimitives();
180 
181         for (auto& prim : dotfieldPrimitives) {
182             const auto& dfc = dotfieldManager_.Get(prim.entity);
183             prim.touch = dfc.touchPosition;
184             prim.touchDirection = dfc.touchDirection;
185             prim.touchRadius = dfc.touchRadius;
186             prim.pointScale = dfc.pointScale;
187             if (worldMatrixManager_.HasComponent(prim.entity)) {
188                 WorldMatrixComponent wc = worldMatrixManager_.Get(prim.entity);
189                 prim.matrix = wc.matrix;
190             }
191         }
192     }
193     return frameRenderingQueued;
194 }
195 
OnComponentEvent( EventType type, const IComponentManager& componentManager, array_view<const Entity> entities)196 void DotfieldSystem::OnComponentEvent(
197     EventType type, const IComponentManager& componentManager, array_view<const Entity> entities)
198 {
199     RenderDataStoreDefaultDotfield* dsDefaultDotfield = static_cast<RenderDataStoreDefaultDotfield*>(
200         renderDataStoreManager_.GetRenderDataStore("RenderDataStoreDefaultDotfield"));
201     switch (type) {
202         case EventType::CREATED:
203             for (const auto& entity : entities) {
204                 if (worldMatrixManager_.HasComponent(entity)) {
205                     WorldMatrixComponent wc = worldMatrixManager_.Get(entity);
206                     DotfieldComponent dfc = dotfieldManager_.Get(entity);
207 
208                     RenderDataDefaultDotfield::DotfieldPrimitive prim;
209                     prim.entity = entity;
210                     prim.matrix = wc.matrix;
211                     prim.touch = dfc.touchPosition;
212                     prim.touchDirection = dfc.touchDirection;
213                     prim.touchRadius = dfc.touchRadius;
214                     prim.colors = { dfc.color0, dfc.color1, dfc.color2, dfc.color3 };
215                     prim.size = { static_cast<uint32_t>(dfc.size.x), static_cast<uint32_t>(dfc.size.y) };
216                     dsDefaultDotfield->AddDotfieldPrimitive(prim);
217                 }
218             }
219             break;
220 
221         case EventType::DESTROYED:
222             for (const auto& entity : entities) {
223                 dsDefaultDotfield->RemoveDotfieldPrimitive(entity);
224             }
225             break;
226 
227         case EventType::MODIFIED:
228             break;
229     }
230 }
231 
232 } // namespace
233 
234 namespace Dotfield {
IDotfieldSystemInstance(IEcs& ecs)235 CORE_NS::ISystem* IDotfieldSystemInstance(IEcs& ecs)
236 {
237     return new DotfieldSystem(ecs);
238 }
IDotfieldSystemDestroy(CORE_NS::ISystem* instance)239 void IDotfieldSystemDestroy(CORE_NS::ISystem* instance)
240 {
241     delete static_cast<DotfieldSystem*>(instance);
242 }
243 } // namespace Dotfield
244