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