• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cmath>
19 #include <random>
20 
21 #include <3d/ecs/components/material_component.h>
22 #include <3d/ecs/components/mesh_component.h>
23 #include <3d/ecs/components/render_handle_component.h>
24 #include <3d/ecs/components/render_mesh_component.h>
25 #include <3d/ecs/components/transform_component.h>
26 #include <3d/ecs/components/world_matrix_component.h>
27 #include <3d/ecs/systems/intf_render_preprocessor_system.h>
28 #include <base/containers/fixed_string.h>
29 #include <base/containers/unordered_map.h>
30 #include <base/math/matrix_util.h>
31 #include <base/math/quaternion_util.h>
32 #include <base/math/vector_util.h>
33 #include <core/ecs/intf_component_manager.h>
34 #include <core/ecs/intf_ecs.h>
35 #include <core/implementation_uids.h>
36 #include <core/intf_engine.h>
37 #include <core/plugin/intf_class_factory.h>
38 #include <core/property/intf_property_api.h>
39 #include <core/property/intf_property_handle.h>
40 #include <core/property_tools/property_api_impl.h>
41 #include <core/property_tools/property_api_impl.inl>
42 #include <core/property_tools/property_data.h>
43 #include <core/property_tools/property_macros.h>
44 #include <render/datastore/intf_render_data_store_manager.h>
45 #include <render/device/intf_device.h>
46 #include <render/device/intf_gpu_resource_manager.h>
47 #include <render/device/intf_shader_manager.h>
48 #include <render/implementation_uids.h>
49 
50 #include "dotfield/ecs/components/dotfield_component.h"
51 #include "render/render_data_store_default_dotfield.h"
52 
53 namespace {
54 #include "app/shaders/common/dotfield_struct_common.h"
55 } // namespace
56 
57 using namespace BASE_NS;
58 using namespace CORE_NS;
59 using namespace RENDER_NS;
60 using namespace CORE3D_NS;
61 using namespace Dotfield;
62 namespace {
63 class DotfieldSystem final : public IDotfieldSystem, private IEcs::ComponentListener {
64 public:
65     explicit DotfieldSystem(IEcs& aECS);
66     ~DotfieldSystem();
67 
68     // ISystem
69     string_view GetName() const override;
70     Uid GetUid() const override;
71 
72     IPropertyHandle* GetProperties() override;
73     const IPropertyHandle* GetProperties() const override;
74     void SetProperties(const IPropertyHandle&) override;
75 
76     bool IsActive() const override;
77     void SetActive(bool state) override;
78 
79     void Initialize() override;
80     void Uninitialize() override;
81     bool Update(bool frameRenderingQueued, uint64_t time, uint64_t delta) override;
82 
83     const IEcs& GetECS() const override;
84 
85     // Listener
86     void OnComponentEvent(
87         EventType type, const IComponentManager& componentManager, array_view<const Entity> entities) override;
88 
89     // IDotfieldSystem
90 
91 private:
92     void UpdateRenderDataStore();
93 
94     struct PropertyData {
95         float speed { 1.f };
96     };
97 
98     PROPERTY_LIST(PropertyData, ComponentMetadata, MEMBER_PROPERTY(speed, "Simulation speed", 0))
99 
100     bool active_ { true };
101     IEcs& ecs_;
102     IWorldMatrixComponentManager* worldMatrixManager_ { nullptr };
103     IMaterialComponentManager* materialManager_ { nullptr };
104     IMeshComponentManager* meshManager_ { nullptr };
105     IRenderMeshComponentManager* renderMeshManager_ { nullptr };
106     IRenderHandleComponentManager* renderHandleManager_ { nullptr };
107     IDotfieldComponentManager* dotfieldManager_ { nullptr };
108     IRenderDataStoreManager* renderDataStoreManager_ { nullptr };
109     EntityReference shader_;
110     PropertyData props_ { 1.f };
111 
112     PropertyApiImpl<PropertyData> propertyApi_ = PropertyApiImpl<PropertyData>(&props_, ComponentMetadata);
113     BASE_NS::refcnt_ptr<IRenderDataStoreDefaultDotfield> dsDefaultDotfield_;
114 };
115 
DotfieldSystem(IEcs & ecs)116 DotfieldSystem::DotfieldSystem(IEcs& ecs)
117     : ecs_(ecs), worldMatrixManager_(GetManager<IWorldMatrixComponentManager>(ecs)),
118       materialManager_(GetManager<IMaterialComponentManager>(ecs)),
119       meshManager_(GetManager<IMeshComponentManager>(ecs)),
120       renderMeshManager_(GetManager<IRenderMeshComponentManager>(ecs)),
121       renderHandleManager_(GetManager<IRenderHandleComponentManager>(ecs)),
122       dotfieldManager_(GetManager<IDotfieldComponentManager>(ecs))
123 {
124     IClassRegister* classRegister = ecs_.GetClassFactory().GetInterface<IClassRegister>();
125     if (classRegister) {
126         if (IRenderContext* renderContext = GetInstance<IRenderContext>(*classRegister, UID_RENDER_CONTEXT);
127             renderContext) {
128             renderDataStoreManager_ = &renderContext->GetRenderDataStoreManager();
129 
130             const IShaderManager& shaderMgr = renderContext->GetDevice().GetShaderManager();
131             auto shaderHandle = shaderMgr.GetShaderHandle("dotfieldshaders://shader/default_material_dotfield.shader");
132 
133             shader_ = ecs.GetEntityManager().CreateReferenceCounted();
134             renderHandleManager_->Create(shader_);
135             renderHandleManager_->Write(shader_)->reference = shaderHandle;
136         }
137     }
138     if (dotfieldManager_) {
139         ecs_.AddListener(*dotfieldManager_, *this);
140     }
141 }
142 
~DotfieldSystem()143 DotfieldSystem ::~DotfieldSystem()
144 {
145     if (dotfieldManager_) {
146         ecs_.RemoveListener(*dotfieldManager_, *this);
147     }
148 }
149 
SetActive(bool state)150 void DotfieldSystem::SetActive(bool state)
151 {
152     active_ = state;
153 }
154 
IsActive() const155 bool DotfieldSystem::IsActive() const
156 {
157     return active_;
158 }
159 
GetName() const160 string_view DotfieldSystem::GetName() const
161 {
162     return Dotfield::GetName(this);
163 }
164 
GetUid() const165 Uid DotfieldSystem::GetUid() const
166 {
167     return UID;
168 }
169 
GetProperties()170 IPropertyHandle* DotfieldSystem::GetProperties()
171 {
172     return propertyApi_.GetData();
173 }
174 
GetProperties() const175 const IPropertyHandle* DotfieldSystem::GetProperties() const
176 {
177     return propertyApi_.GetData();
178 }
179 
SetProperties(const IPropertyHandle & dataHandle)180 void DotfieldSystem::SetProperties(const IPropertyHandle& dataHandle)
181 {
182     if (dataHandle.Owner() != &propertyApi_) {
183         return;
184     }
185     if (auto data = ScopedHandle<const PropertyData>(&dataHandle); data) {
186         props_ = *data;
187     }
188 }
189 
GetECS() const190 const IEcs& DotfieldSystem::GetECS() const
191 {
192     return ecs_;
193 }
194 
Initialize()195 void DotfieldSystem::Initialize() {}
196 
Uninitialize()197 void DotfieldSystem::Uninitialize() {}
198 
Update(bool frameRenderingQueued,uint64_t time,uint64_t delta)199 bool DotfieldSystem::Update(bool frameRenderingQueued, uint64_t time, uint64_t delta)
200 {
201     if (!active_) {
202         return false;
203     }
204     if (!(worldMatrixManager_ && dotfieldManager_ && renderDataStoreManager_)) {
205         return false;
206     }
207     if (!dsDefaultDotfield_) {
208         UpdateRenderDataStore();
209     }
210     if (dsDefaultDotfield_) {
211         // delta time from us to s
212         const auto timeStep = static_cast<float>(delta) * 0.000001f * props_.speed;
213         dsDefaultDotfield_->SetTimeStep(timeStep);
214         dsDefaultDotfield_->SetTime(static_cast<float>(time) * 0.000001f);
215         const float dsTime = dsDefaultDotfield_->GetTime();
216         array_view<RenderDataDefaultDotfield::DotfieldPrimitive> dotfieldPrimitives =
217             dsDefaultDotfield_->GetDotfieldPrimitives();
218         const auto& bufferData = dsDefaultDotfield_->GetBufferData();
219         auto buffersIt = bufferData.buffers.cbegin();
220         for (auto& prim : dotfieldPrimitives) {
221             const auto& dfc = dotfieldManager_->Get(prim.entity);
222             prim.touch = dfc.touchPosition;
223             prim.touchDirection = dfc.touchDirection;
224             prim.touchRadius = dfc.touchRadius;
225             prim.pointScale = dfc.pointScale;
226             prim.colors = { dfc.color0, dfc.color1, dfc.color2, dfc.color3 };
227             if (worldMatrixManager_->HasComponent(prim.entity)) {
228                 WorldMatrixComponent wc = worldMatrixManager_->Get(prim.entity);
229                 prim.matrix = wc.matrix;
230             }
231             if (auto meshHandle = meshManager_->Write(prim.entity)) {
232                 const auto& buffer = buffersIt->dataBuffer[bufferData.currFrameIndex];
233                 GpuBufferDesc desc;
234                 IClassRegister* classRegister = ecs_.GetClassFactory().GetInterface<IClassRegister>();
235                 if (classRegister) {
236                     if (IRenderContext* renderContext = GetInstance<IRenderContext>(*classRegister, UID_RENDER_CONTEXT);
237                         renderContext) {
238                         desc = renderContext->GetDevice().GetGpuResourceManager().GetBufferDescriptor(buffer);
239                     }
240                 }
241                 meshHandle->submeshes[0U].bufferAccess[MeshComponent::Submesh::DM_VB_POS].buffer =
242                     GetOrCreateEntityReference(ecs_, buffersIt->dataBuffer[bufferData.currFrameIndex]);
243                 meshHandle->submeshes[0U].bufferAccess[MeshComponent::Submesh::DM_VB_POS].byteSize = desc.byteSize;
244             }
245             if (auto materialHandle = materialManager_->Write(prim.entity)) {
246                 materialHandle->materialShader.shader = shader_;
247                 BASE_NS::CloneData(
248                     &materialHandle->textures[1].factor, sizeof(Math::Vec4), &prim.colors, sizeof(Math::UVec4));
249                 materialHandle->textures[2].factor = { dsTime, dfc.pointScale, 0.f, 0.f }; // 2: texture idx
250             }
251         }
252     }
253     return frameRenderingQueued;
254 }
255 
OnComponentEvent(EventType type,const IComponentManager & componentManager,array_view<const Entity> entities)256 void DotfieldSystem::OnComponentEvent(
257     EventType type, const IComponentManager& componentManager, array_view<const Entity> entities)
258 {
259     if (!(worldMatrixManager_ && dotfieldManager_ && renderDataStoreManager_)) {
260         return;
261     }
262     UpdateRenderDataStore();
263     if (!dsDefaultDotfield_) {
264         return;
265     }
266     switch (type) {
267         case EventType::CREATED:
268             for (const auto& entity : entities) {
269                 if (worldMatrixManager_->HasComponent(entity)) {
270                     WorldMatrixComponent wc = worldMatrixManager_->Get(entity);
271                     DotfieldComponent dfc = dotfieldManager_->Get(entity);
272 
273                     RenderDataDefaultDotfield::DotfieldPrimitive prim;
274                     prim.entity = entity;
275                     prim.matrix = wc.matrix;
276                     prim.touch = dfc.touchPosition;
277                     prim.touchDirection = dfc.touchDirection;
278                     prim.touchRadius = dfc.touchRadius;
279                     prim.colors = { dfc.color0, dfc.color1, dfc.color2, dfc.color3 };
280                     prim.size = { static_cast<uint32_t>(dfc.size.x), static_cast<uint32_t>(dfc.size.y) };
281                     const auto index = static_cast<uint32_t>(dsDefaultDotfield_->GetDotfieldPrimitives().size());
282                     dsDefaultDotfield_->AddDotfieldPrimitive(prim);
283 
284                     materialManager_->Create(entity);
285                     if (auto materialHandle = materialManager_->Write(entity)) {
286                         materialHandle->type = MaterialComponent::Type::CUSTOM;
287                         materialHandle->materialShader.shader = shader_;
288                         BASE_NS::CloneData(
289                             &materialHandle->textures[1].factor, sizeof(Math::Vec4), &prim.colors, sizeof(Math::UVec4));
290                         materialHandle->textures[2].factor = { 0.f, dfc.pointScale, 0.f, 0.f }; // 2: texture idx
291                     }
292                     meshManager_->Create(entity);
293                     if (auto meshHandle = meshManager_->Write(entity)) {
294                         auto& submesh = meshHandle->submeshes.emplace_back();
295                         submesh.material = entity;
296                         submesh.aabbMin = { -10.f, -10.f, -10.f };
297                         submesh.aabbMax = { 10.f, 10.f, 10.f };
298                         submesh.instanceCount = prim.size.x * prim.size.y;
299                         submesh.vertexCount = 1;
300 
301                         meshHandle->aabbMin = { -10.f, -10.f, -10.f };
302                         meshHandle->aabbMax = { 10.f, 10.f, 10.f };
303                     }
304 
305                     renderMeshManager_->Create(entity);
306                     renderMeshManager_->Write(entity)->mesh = entity;
307                     renderMeshManager_->Write(entity)->customData[0] = { prim.size.x, prim.size.y, index, 0U };
308                 }
309             }
310             break;
311 
312         case EventType::DESTROYED:
313             for (const auto& entity : entities) {
314                 dsDefaultDotfield_->RemoveDotfieldPrimitive(entity);
315             }
316             break;
317 
318         case EventType::MODIFIED:
319             break;
320 
321         case EventType::MOVED:
322             break;
323     }
324 }
325 
UpdateRenderDataStore()326 void DotfieldSystem::UpdateRenderDataStore()
327 {
328     if (!dsDefaultDotfield_) {
329         if (auto preprocessor = GetSystem<IRenderPreprocessorSystem>(ecs_)) {
330             if (auto propertyHandle =
331                     ScopedHandle<const IRenderPreprocessorSystem::Properties>(preprocessor->GetProperties())) {
332                 const auto name = propertyHandle->dataStorePrefix + "RenderDataStoreDefaultDotfield";
333                 dsDefaultDotfield_ = refcnt_ptr<IRenderDataStoreDefaultDotfield>(
334                     renderDataStoreManager_->Create(IRenderDataStoreDefaultDotfield::UID, name.data()));
335             }
336         }
337     }
338 }
339 } // namespace
340 
341 namespace Dotfield {
IDotfieldSystemInstance(IEcs & ecs)342 CORE_NS::ISystem* IDotfieldSystemInstance(IEcs& ecs)
343 {
344     return new DotfieldSystem(ecs);
345 }
IDotfieldSystemDestroy(CORE_NS::ISystem * instance)346 void IDotfieldSystemDestroy(CORE_NS::ISystem* instance)
347 {
348     delete static_cast<DotfieldSystem*>(instance);
349 }
350 } // namespace Dotfield
351