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 <3d/ecs/components/post_process_configuration_component.h>
17 #include <3d/ecs/components/render_handle_component.h>
18 #include <base/containers/array_view.h>
19 #include <base/containers/string.h>
20 #include <base/containers/type_traits.h>
21 #include <core/ecs/intf_ecs.h>
22 #include <core/intf_engine.h>
23 #include <render/datastore/intf_render_data_store_post_process.h>
24 #include <render/datastore/render_data_store_render_pods.h>
25 #include <render/device/intf_shader_manager.h>
26 #include <render/implementation_uids.h>
27 #include <render/intf_render_context.h>
28 
29 #include "ComponentTools/base_manager.h"
30 #include "ComponentTools/base_manager.inl"
31 #include "util/json_util.h"
32 #include "util/property_util.h"
33 
34 #define IMPLEMENT_MANAGER
35 #include "PropertyTools/property_macros.h"
36 
37 CORE_BEGIN_NAMESPACE()
38 using CORE3D_NS::PostProcessConfigurationComponent;
39 
40 DECLARE_PROPERTY_TYPE(CORE_NS::IPropertyHandle*);
41 DECLARE_PROPERTY_TYPE(RENDER_NS::RenderHandle);
42 DECLARE_PROPERTY_TYPE(RENDER_NS::RenderHandleReference);
43 DECLARE_PROPERTY_TYPE(PostProcessConfigurationComponent::PostProcessEffect);
44 DECLARE_PROPERTY_TYPE(BASE_NS::vector<PostProcessConfigurationComponent::PostProcessEffect>);
45 
46 BEGIN_METADATA(
47     PostProcessConfigurationComponentPostProcessEffectMetaData, PostProcessConfigurationComponent::PostProcessEffect)
48 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, name, "Effect Name", 0)
49 DECL_PROPERTY2(
50     PostProcessConfigurationComponent::PostProcessEffect, globalUserFactorIndex, "Global User Factor Index", 0)
51 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, shader, "Shader", 0)
52 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, enabled, "Enabled", 0)
53 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, flags, "Additional Non Typed Flags", 0)
54 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, factor, "Global Factor", 0)
55 DECL_PROPERTY2(PostProcessConfigurationComponent::PostProcessEffect, customProperties, "Custom Properties", 0)
56 END_METADATA(
57     PostProcessConfigurationComponentPostProcessEffectMetaData, PostProcessConfigurationComponent::PostProcessEffect)
58 
59 // Needed to get containerMethods through MetaData() -> Property -> metaData -> containerMethods
60 DECLARE_CONTAINER_API(PPCC_PPE, PostProcessConfigurationComponent::PostProcessEffect);
61 CORE_END_NAMESPACE()
62 
63 CORE3D_BEGIN_NAMESPACE()
64 using namespace BASE_NS;
65 using namespace CORE_NS;
66 using namespace RENDER_NS;
67 
68 namespace {
69 constexpr uint32_t CUSTOM_PROPERTY_POD_CONTAINER_BYTE_SIZE { PostProcessConstants::USER_LOCAL_FACTOR_BYTE_SIZE };
70 constexpr string_view CUSTOM_PROPERTIES = "customProperties";
71 constexpr string_view CUSTOM_PROPERTY_DATA = "data";
72 constexpr string_view NAME = "name";
73 constexpr string_view DISPLAY_NAME = "displayName";
74 
UpdateCustomPropertyMetadata(const json::value & customProperties,CustomPropertyPodContainer & properties)75 void UpdateCustomPropertyMetadata(const json::value& customProperties, CustomPropertyPodContainer& properties)
76 {
77     if (customProperties && customProperties.is_array()) {
78         for (const auto& ref : customProperties.array_) {
79             if (const auto customProps = ref.find(CUSTOM_PROPERTIES); customProps && customProps->is_array()) {
80                 // process custom properties i.e. local factors
81                 for (const auto& propRef : customProps->array_) {
82                     if (const auto customData = propRef.find(CUSTOM_PROPERTY_DATA); customData) {
83                         // reserve the property count
84                         properties.ReservePropertyCount(customData->array_.size());
85                         for (const auto& dataValue : customData->array_) {
86                             if (dataValue.is_object()) {
87                                 string_view name;
88                                 string_view displayName;
89                                 string_view type;
90                                 const json::value* value = nullptr;
91                                 for (const auto& dataObject : dataValue.object_) {
92                                     if (dataObject.key == NAME && dataObject.value.is_string()) {
93                                         name = dataObject.value.string_;
94                                     } else if (dataObject.key == DISPLAY_NAME && dataObject.value.is_string()) {
95                                         displayName = dataObject.value.string_;
96                                     } else if (dataObject.key == "type" && dataObject.value.is_string()) {
97                                         type = dataObject.value.string_;
98                                     } else if (dataObject.key == "value") {
99                                         value = &dataObject.value;
100                                     }
101                                 }
102 
103                                 const PropertyTypeDecl typeDecl =
104                                     CustomPropertyPodHelper::GetPropertyTypeDeclaration(type);
105                                 const size_t align = CustomPropertyPodHelper::GetPropertyTypeAlignment(typeDecl);
106                                 const size_t offset = [](size_t value, size_t align) -> size_t {
107                                     if (align == 0U) {
108                                         return value;
109                                     }
110                                     return ((value + align - 1U) / align) * align;
111                                 }(properties.GetByteSize(), align);
112                                 properties.AddOffsetProperty(name, displayName, offset, typeDecl);
113                                 CustomPropertyPodHelper::SetCustomPropertyBlobValue(
114                                     typeDecl, value, properties, offset);
115                             }
116                         }
117                     }
118                 }
119             }
120         }
121     }
122 }
123 } // namespace
124 
125 class PostProcessConfigurationComponentManager final : public IPostProcessConfigurationComponentManager,
126                                                        public IPropertyApi {
127     using ComponentId = IComponentManager::ComponentId;
128 
129 public:
130     explicit PostProcessConfigurationComponentManager(IEcs& ecs) noexcept;
131     ~PostProcessConfigurationComponentManager() override;
132 
133     // IPropertyApi
134     size_t PropertyCount() const override;
135     const Property* MetaData(size_t index) const override;
136     array_view<const Property> MetaData() const override;
137     IPropertyHandle* Create() const override;
138     IPropertyHandle* Clone(const IPropertyHandle*) const override;
139     void Release(IPropertyHandle*) const override;
140     uint64_t Type() const override;
141 
142     // IComponentManager
143     virtual string_view GetName() const override;
144     virtual Uid GetUid() const override;
145     size_t GetComponentCount() const override;
146     const IPropertyApi& GetPropertyApi() const override;
147     Entity GetEntity(ComponentId index) const override;
148     uint32_t GetComponentGeneration(ComponentId index) const override;
149     bool HasComponent(Entity entity) const override;
150     IComponentManager::ComponentId GetComponentId(Entity entity) const override;
151     void Create(Entity entity) override;
152     bool Destroy(Entity entity) override;
153     void Gc() override;
154     void Destroy(array_view<const Entity> gcList) override;
155     vector<Entity> GetAddedComponents() override;
156     vector<Entity> GetRemovedComponents() override;
157     vector<Entity> GetUpdatedComponents() override;
158     CORE_NS::ComponentManagerModifiedFlags GetModifiedFlags() const override;
159     void ClearModifiedFlags() override;
160     uint32_t GetGenerationCounter() const override;
161     void SetData(Entity entity, const IPropertyHandle& dataHandle) override;
162     const IPropertyHandle* GetData(Entity entity) const override;
163     IPropertyHandle* GetData(Entity entity) override;
164     void SetData(ComponentId index, const IPropertyHandle& dataHandle) override;
165     const IPropertyHandle* GetData(ComponentId index) const override;
166     IPropertyHandle* GetData(ComponentId index) override;
167     IEcs& GetEcs() const override;
168 
169     // IPostProcessConfigurationComponentManager
170     PostProcessConfigurationComponent Get(ComponentId index) const override;
171     PostProcessConfigurationComponent Get(Entity entity) const override;
172     void Set(ComponentId index, const PostProcessConfigurationComponent& aData) override;
173     void Set(Entity entity, const PostProcessConfigurationComponent& aData) override;
174     ScopedHandle<const PostProcessConfigurationComponent> Read(ComponentId index) const override;
175     ScopedHandle<const PostProcessConfigurationComponent> Read(Entity entity) const override;
176     ScopedHandle<PostProcessConfigurationComponent> Write(ComponentId index) override;
177     ScopedHandle<PostProcessConfigurationComponent> Write(Entity entity) override;
178 
179     // internal, non-public
180     void Updated(Entity entity);
181 
182 private:
183     BEGIN_PROPERTY(PostProcessConfigurationComponent, componentProperties_)
184 #include <3d/ecs/components/post_process_configuration_component.h>
185     END_PROPERTY();
186     static constexpr array_view<const Property> componentMetaData_ { componentProperties_,
187         countof(componentProperties_) };
188 
189     bool IsMatchingHandle(const IPropertyHandle& handle);
190 
191     static constexpr uint64_t typeHash_ =
192         BASE_NS::CompileTime::FNV1aHash(CORE_NS::GetName<PostProcessConfigurationComponent>().data(),
193             CORE_NS::GetName<PostProcessConfigurationComponent>().size());
194 
195     class ComponentHandle : public IPropertyHandle, IPropertyApi {
196     public:
197         ComponentHandle() = delete;
198         ComponentHandle(PostProcessConfigurationComponentManager* owner, Entity entity) noexcept;
199         ComponentHandle(PostProcessConfigurationComponentManager* owner, Entity entity,
200             const PostProcessConfigurationComponent& data) noexcept;
201         ~ComponentHandle() override = default;
202         ComponentHandle(const ComponentHandle& other) = delete;
203         ComponentHandle(ComponentHandle&& other) noexcept;
204         ComponentHandle& operator=(const ComponentHandle& other) = delete;
205         ComponentHandle& operator=(ComponentHandle&& other) noexcept;
206 
207         // IPropertyHandle
208         const IPropertyApi* Owner() const override;
209         size_t Size() const override;
210         const void* RLock() const override;
211         void RUnlock() const override;
212         void* WLock() override;
213         void WUnlock() override;
214 
215         // IPropertyApi
216         size_t PropertyCount() const override;
217         const Property* MetaData(size_t index) const override;
218         array_view<const Property> MetaData() const override;
219         uint64_t Type() const override;
220         IPropertyHandle* Create() const override;
221         IPropertyHandle* Clone(const IPropertyHandle* src) const override;
222         void Release(IPropertyHandle* handle) const override;
223 
224         void UpdateMetadata();
225 
226         PostProcessConfigurationComponentManager* manager_ { nullptr };
227         Entity entity_;
228         uint32_t generation_ { 0u };
229         bool dirty_ { false };
230         mutable std::atomic_int32_t rLocked_ { 0 };
231         mutable bool wLocked_ { false };
232         PostProcessConfigurationComponent data_;
233 
234         // shader per single post process
235         vector<Entity> effectShaders_;
236         // custom property blob per single post process shader
237         vector<unique_ptr<CustomPropertyPodContainer>> customProperties_;
238     };
239 
240     IEcs& ecs_;
241     IShaderManager& shaderManager_;
242     IRenderHandleComponentManager* renderHandleManager_ { nullptr };
243 
244     uint32_t generationCounter_ { 0u };
245     uint32_t modifiedFlags_ { 0u };
246     unordered_map<Entity, ComponentId> entityComponent_;
247     vector<ComponentHandle> components_;
248     BASE_NS::vector<Entity> added_;
249     BASE_NS::vector<Entity> removed_;
250     BASE_NS::vector<Entity> updated_;
251 };
252 
PostProcessConfigurationComponentManager(IEcs & ecs)253 PostProcessConfigurationComponentManager::PostProcessConfigurationComponentManager(IEcs& ecs) noexcept
254     : ecs_(ecs), shaderManager_(GetInstance<IRenderContext>(
255                      *ecs.GetClassFactory().GetInterface<IClassRegister>(), UID_RENDER_CONTEXT)
256                                     ->GetDevice()
257                                     .GetShaderManager()),
258       renderHandleManager_(GetManager<IRenderHandleComponentManager>(ecs))
259 {}
260 
261 PostProcessConfigurationComponentManager::~PostProcessConfigurationComponentManager() = default;
262 
263 // IPropertyApi
PropertyCount() const264 size_t PostProcessConfigurationComponentManager::PropertyCount() const
265 {
266     return componentMetaData_.size();
267 }
268 
MetaData(size_t index) const269 const Property* PostProcessConfigurationComponentManager::MetaData(size_t index) const
270 {
271     if (index < componentMetaData_.size()) {
272         return &componentMetaData_[index];
273     }
274     return nullptr;
275 }
276 
MetaData() const277 array_view<const Property> PostProcessConfigurationComponentManager::MetaData() const
278 {
279     return componentMetaData_;
280 }
281 
Create() const282 IPropertyHandle* PostProcessConfigurationComponentManager::Create() const
283 {
284     return new ComponentHandle(const_cast<PostProcessConfigurationComponentManager*>(this), {}, {});
285 }
286 
Clone(const IPropertyHandle * src) const287 IPropertyHandle* PostProcessConfigurationComponentManager::Clone(const IPropertyHandle* src) const
288 {
289     if (src) {
290         auto owner = src->Owner();
291         if (owner == this) {
292             auto* h = static_cast<const ComponentHandle*>(src);
293             return new ComponentHandle(const_cast<PostProcessConfigurationComponentManager*>(this), {}, h->data_);
294         } else if (owner) {
295             return owner->Clone(src);
296         }
297     }
298     return nullptr;
299 }
300 
Release(IPropertyHandle * dst) const301 void PostProcessConfigurationComponentManager::Release(IPropertyHandle* dst) const
302 {
303     if (dst) {
304         auto owner = dst->Owner();
305         if (owner == this) {
306             // we can only destroy things we "own" (know)
307             auto* handle = static_cast<ComponentHandle*>(dst);
308             if (auto id = GetComponentId(handle->entity_); id != IComponentManager::INVALID_COMPONENT_ID) {
309                 if (&components_[id] == handle) {
310                     // This is one of the components (bound to an entity) so do nothing
311                     return;
312                 }
313             }
314             delete handle;
315         } else if (owner) {
316             owner->Release(dst);
317         }
318     }
319 }
320 
Type() const321 uint64_t PostProcessConfigurationComponentManager::Type() const
322 {
323     return typeHash_;
324 }
325 
326 // IComponentManager
GetName() const327 string_view PostProcessConfigurationComponentManager::GetName() const
328 {
329     constexpr auto name = CORE_NS::GetName<PostProcessConfigurationComponent>();
330     return name;
331 }
332 
GetUid() const333 Uid PostProcessConfigurationComponentManager::GetUid() const
334 {
335     return IPostProcessConfigurationComponentManager::UID;
336 }
337 
GetComponentCount() const338 size_t PostProcessConfigurationComponentManager::GetComponentCount() const
339 {
340     return components_.size();
341 }
342 
GetPropertyApi() const343 const IPropertyApi& PostProcessConfigurationComponentManager::GetPropertyApi() const
344 {
345     return *this;
346 }
347 
GetEntity(ComponentId index) const348 Entity PostProcessConfigurationComponentManager::GetEntity(ComponentId index) const
349 {
350     if (index < components_.size()) {
351         return components_[index].entity_;
352     }
353     return Entity();
354 }
355 
GetComponentGeneration(ComponentId index) const356 uint32_t PostProcessConfigurationComponentManager::GetComponentGeneration(ComponentId index) const
357 {
358     if (index < components_.size()) {
359         return components_[index].generation_;
360     }
361     return 0;
362 }
363 
HasComponent(Entity entity) const364 bool PostProcessConfigurationComponentManager::HasComponent(Entity entity) const
365 {
366     return GetComponentId(entity) != IComponentManager::INVALID_COMPONENT_ID;
367 }
368 
GetComponentId(Entity entity) const369 IComponentManager::ComponentId PostProcessConfigurationComponentManager::GetComponentId(Entity entity) const
370 {
371     if (auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
372         return it->second;
373     }
374     return IComponentManager::INVALID_COMPONENT_ID;
375 }
376 
Create(Entity entity)377 void PostProcessConfigurationComponentManager::Create(Entity entity)
378 {
379     if (CORE_NS::EntityUtil::IsValid(entity)) {
380         if (auto it = entityComponent_.find(entity); it == entityComponent_.end()) {
381             entityComponent_.insert({ entity, static_cast<ComponentId>(components_.size()) });
382             auto& component = components_.emplace_back(this, entity);
383             added_.push_back(entity);
384             modifiedFlags_ |= CORE_NS::CORE_COMPONENT_MANAGER_COMPONENT_ADDED_BIT;
385             generationCounter_++;
386 
387             // lock/unlock for toggling component updated behavior.
388             component.WLock();
389             component.WUnlock();
390         } else {
391             if (auto dst = ScopedHandle<PostProcessConfigurationComponent>(&components_[it->second]); dst) {
392                 *dst = {};
393             }
394         }
395     }
396 }
397 
Destroy(Entity entity)398 bool PostProcessConfigurationComponentManager::Destroy(Entity entity)
399 {
400     if (CORE_NS::EntityUtil::IsValid(entity)) {
401         if (auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
402             components_[it->second].entity_ = {}; // invalid entity. (marks it as ready for re-use)
403             entityComponent_.erase(it);
404             removed_.push_back(entity);
405             modifiedFlags_ |= CORE_NS::CORE_COMPONENT_MANAGER_COMPONENT_REMOVED_BIT;
406             generationCounter_++;
407             return true;
408         }
409     }
410     return false;
411 }
412 
Gc()413 void PostProcessConfigurationComponentManager::Gc()
414 {
415     const bool hasRemovedComponents = modifiedFlags_ & CORE_NS::CORE_COMPONENT_MANAGER_COMPONENT_REMOVED_BIT;
416     if (!hasRemovedComponents) {
417         return;
418     }
419     ComponentId componentCount = static_cast<ComponentId>(components_.size());
420     for (ComponentId id = 0; id < componentCount;) {
421         auto* it = &components_[id];
422         // invalid entity, if so clean garbage
423         if (!CORE_NS::EntityUtil::IsValid(it->entity_)) {
424             // find last valid and swap with it
425             for (ComponentId rid = componentCount - 1; rid > id; rid--) {
426                 auto* rit = &components_[rid];
427                 // valid entity? if so swap the components.
428                 if (CORE_NS::EntityUtil::IsValid(rit->entity_)) {
429                     // fix the entityComponent_ map (update the component id for the entity)
430                     entityComponent_[rit->entity_] = id;
431                     *it = move(*rit);
432                     break;
433                 }
434             }
435             componentCount--;
436             continue;
437         }
438         id++;
439     }
440     if (components_.size() > componentCount) {
441         auto diff = static_cast<typename decltype(components_)::difference_type>(componentCount);
442         components_.erase(components_.cbegin() + diff, components_.cend());
443     }
444 }
445 
Destroy(const array_view<const Entity> gcList)446 void PostProcessConfigurationComponentManager::Destroy(const array_view<const Entity> gcList)
447 {
448     for (const Entity e : gcList) {
449         Destroy(e);
450     }
451 }
452 
GetAddedComponents()453 vector<Entity> PostProcessConfigurationComponentManager::GetAddedComponents()
454 {
455     return BASE_NS::move(added_);
456 }
457 
GetRemovedComponents()458 vector<Entity> PostProcessConfigurationComponentManager::GetRemovedComponents()
459 {
460     return BASE_NS::move(removed_);
461 }
462 
GetUpdatedComponents()463 vector<Entity> PostProcessConfigurationComponentManager::GetUpdatedComponents()
464 {
465     vector<Entity> updated;
466     if (modifiedFlags_ & MODIFIED) {
467         modifiedFlags_ &= ~MODIFIED;
468         updated.reserve(components_.size() / 2); // 2: half
469         for (auto& handle : components_) {
470             if (handle.dirty_) {
471                 handle.dirty_ = false;
472                 updated.push_back(handle.entity_);
473             }
474         }
475     }
476     return updated;
477 }
478 
GetModifiedFlags() const479 CORE_NS::ComponentManagerModifiedFlags PostProcessConfigurationComponentManager::GetModifiedFlags() const
480 {
481     return modifiedFlags_ & ~MODIFIED;
482 }
483 
ClearModifiedFlags()484 void PostProcessConfigurationComponentManager::ClearModifiedFlags()
485 {
486     modifiedFlags_ &= MODIFIED;
487 }
488 
GetGenerationCounter() const489 uint32_t PostProcessConfigurationComponentManager::GetGenerationCounter() const
490 {
491     return generationCounter_;
492 }
493 
SetData(Entity entity,const IPropertyHandle & dataHandle)494 void PostProcessConfigurationComponentManager::SetData(Entity entity, const IPropertyHandle& dataHandle)
495 {
496     if (!IsMatchingHandle(dataHandle)) {
497         return;
498     }
499     if (const auto src = ScopedHandle<const PostProcessConfigurationComponent>(&dataHandle); src) {
500         if (const auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
501             if (auto dst = ScopedHandle<PostProcessConfigurationComponent>(&components_[it->second]); dst) {
502                 *dst = *src;
503             }
504         }
505     }
506 }
507 
GetData(Entity entity) const508 const IPropertyHandle* PostProcessConfigurationComponentManager::GetData(Entity entity) const
509 {
510     if (CORE_NS::EntityUtil::IsValid(entity)) {
511         if (const auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
512             if (it->second < components_.size()) {
513                 return &components_[it->second];
514             }
515         }
516     }
517     return nullptr;
518 }
519 
GetData(Entity entity)520 IPropertyHandle* PostProcessConfigurationComponentManager::GetData(Entity entity)
521 {
522     if (CORE_NS::EntityUtil::IsValid(entity)) {
523         if (const auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
524             if (it->second < components_.size()) {
525                 return &components_[it->second];
526             }
527         }
528     }
529     return nullptr;
530 }
531 
SetData(ComponentId index,const IPropertyHandle & dataHandle)532 void PostProcessConfigurationComponentManager::SetData(ComponentId index, const IPropertyHandle& dataHandle)
533 {
534     if (!IsMatchingHandle(dataHandle)) {
535         // We could verify the metadata here.
536         // And in copy only the matching properties one-by-one also.
537         return;
538     }
539     if (index < components_.size()) {
540         if (const auto src = ScopedHandle<const PostProcessConfigurationComponent>(&dataHandle); src) {
541             if (auto dst = ScopedHandle<PostProcessConfigurationComponent>(&components_[index]); dst) {
542                 *dst = *src;
543             }
544         }
545     }
546 }
547 
GetData(ComponentId index) const548 const IPropertyHandle* PostProcessConfigurationComponentManager::GetData(ComponentId index) const
549 {
550     if (index < components_.size()) {
551         return &components_[index];
552     }
553     return nullptr;
554 }
555 
GetData(ComponentId index)556 IPropertyHandle* PostProcessConfigurationComponentManager::GetData(ComponentId index)
557 {
558     if (index < components_.size()) {
559         return &components_[index];
560     }
561     return nullptr;
562 }
563 
GetEcs() const564 IEcs& PostProcessConfigurationComponentManager::GetEcs() const
565 {
566     return ecs_;
567 }
568 
569 // IPostProcessConfigurationComponentManager
Get(ComponentId index) const570 PostProcessConfigurationComponent PostProcessConfigurationComponentManager::Get(ComponentId index) const
571 {
572     if (auto handle = Read(index); handle) {
573         return *handle;
574     }
575     return PostProcessConfigurationComponent {};
576 }
577 
Get(Entity entity) const578 PostProcessConfigurationComponent PostProcessConfigurationComponentManager::Get(Entity entity) const
579 {
580     if (auto handle = Read(entity); handle) {
581         return *handle;
582     }
583     return PostProcessConfigurationComponent {};
584 }
585 
Set(ComponentId index,const PostProcessConfigurationComponent & data)586 void PostProcessConfigurationComponentManager::Set(ComponentId index, const PostProcessConfigurationComponent& data)
587 {
588     if (auto handle = Write(index); handle) {
589         *handle = data;
590     }
591 }
592 
Set(Entity entity,const PostProcessConfigurationComponent & data)593 void PostProcessConfigurationComponentManager::Set(Entity entity, const PostProcessConfigurationComponent& data)
594 {
595     if (CORE_NS::EntityUtil::IsValid(entity)) {
596         if (auto handle = Write(entity); handle) {
597             *handle = data;
598         } else {
599             entityComponent_.insert({ entity, static_cast<ComponentId>(components_.size()) });
600             auto& component = components_.emplace_back(this, entity, data);
601             added_.push_back(entity);
602             modifiedFlags_ |= CORE_NS::CORE_COMPONENT_MANAGER_COMPONENT_ADDED_BIT;
603             generationCounter_++;
604 
605             // lock/unlock for toggling component updated behavior.
606             component.WLock();
607             component.WUnlock();
608         }
609     }
610 }
611 
Read(ComponentId index) const612 ScopedHandle<const PostProcessConfigurationComponent> PostProcessConfigurationComponentManager::Read(
613     ComponentId index) const
614 {
615     return ScopedHandle<const PostProcessConfigurationComponent> { GetData(index) };
616 }
617 
Read(Entity entity) const618 ScopedHandle<const PostProcessConfigurationComponent> PostProcessConfigurationComponentManager::Read(
619     Entity entity) const
620 {
621     return ScopedHandle<const PostProcessConfigurationComponent> { GetData(entity) };
622 }
623 
Write(ComponentId index)624 ScopedHandle<PostProcessConfigurationComponent> PostProcessConfigurationComponentManager::Write(ComponentId index)
625 {
626     return ScopedHandle<PostProcessConfigurationComponent> { GetData(index) };
627 }
628 
Write(Entity entity)629 ScopedHandle<PostProcessConfigurationComponent> PostProcessConfigurationComponentManager::Write(Entity entity)
630 {
631     return ScopedHandle<PostProcessConfigurationComponent> { GetData(entity) };
632 }
633 
634 // Internal
Updated(Entity entity)635 void PostProcessConfigurationComponentManager::Updated(Entity entity)
636 {
637     CORE_ASSERT_MSG(CORE_NS::EntityUtil::IsValid(entity), "Invalid ComponentId, bound to INVALID_ENTITY");
638     modifiedFlags_ |= CORE_NS::CORE_COMPONENT_MANAGER_COMPONENT_UPDATED_BIT | MODIFIED;
639     generationCounter_++;
640 }
641 
IsMatchingHandle(const IPropertyHandle & dataHandle)642 bool PostProcessConfigurationComponentManager::IsMatchingHandle(const IPropertyHandle& dataHandle)
643 {
644     if (dataHandle.Owner() == this) {
645         return true;
646     }
647     if (dataHandle.Owner()->Type() == typeHash_) {
648         return true;
649     }
650     return false;
651 }
652 
653 // Handle implementation
ComponentHandle(PostProcessConfigurationComponentManager * owner,Entity entity)654 PostProcessConfigurationComponentManager::ComponentHandle::ComponentHandle(
655     PostProcessConfigurationComponentManager* owner, Entity entity) noexcept
656     : ComponentHandle(owner, entity, {})
657 {}
658 
ComponentHandle(PostProcessConfigurationComponentManager * owner,Entity entity,const PostProcessConfigurationComponent & data)659 PostProcessConfigurationComponentManager::ComponentHandle::ComponentHandle(
660     PostProcessConfigurationComponentManager* owner, Entity entity,
661     const PostProcessConfigurationComponent& data) noexcept
662     : manager_(owner), entity_(entity), data_(data)
663 {}
664 
ComponentHandle(ComponentHandle && other)665 PostProcessConfigurationComponentManager::ComponentHandle::ComponentHandle(ComponentHandle&& other) noexcept
666     : manager_(other.manager_), entity_(exchange(other.entity_, {})), generation_(exchange(other.generation_, 0u)),
667       rLocked_(other.rLocked_.exchange(0)), wLocked_(exchange(other.wLocked_, false)), data_(exchange(other.data_, {})),
668       customProperties_(exchange(other.customProperties_, {}))
669 {}
670 
671 typename PostProcessConfigurationComponentManager::ComponentHandle&
operator =(ComponentHandle && other)672 PostProcessConfigurationComponentManager::ComponentHandle::operator=(ComponentHandle&& other) noexcept
673 {
674     if (this != &other) {
675         CORE_ASSERT(manager_ == other.manager_);
676         entity_ = exchange(other.entity_, {});
677         generation_ = exchange(other.generation_, 0u);
678         dirty_ = exchange(other.dirty_, false);
679         rLocked_ = other.rLocked_.exchange(0);
680         wLocked_ = exchange(other.wLocked_, false);
681         data_ = exchange(other.data_, {});
682         effectShaders_ = exchange(other.effectShaders_, {});
683         customProperties_ = exchange(other.customProperties_, {});
684     }
685     return *this;
686 }
687 
688 // ComponentHandle IPropertyHandle
Owner() const689 const IPropertyApi* PostProcessConfigurationComponentManager::ComponentHandle::Owner() const
690 {
691     return this;
692 }
693 
Size() const694 size_t PostProcessConfigurationComponentManager::ComponentHandle::Size() const
695 {
696     return sizeof(PostProcessConfigurationComponent);
697 }
698 
RLock() const699 const void* PostProcessConfigurationComponentManager::ComponentHandle::RLock() const
700 {
701     CORE_ASSERT(manager_);
702     CORE_ASSERT(!wLocked_);
703     rLocked_++;
704     return &data_;
705 }
706 
RUnlock() const707 void PostProcessConfigurationComponentManager::ComponentHandle::RUnlock() const
708 {
709     CORE_ASSERT(manager_);
710     CORE_ASSERT(rLocked_ > 0);
711     rLocked_--;
712 }
713 
WLock()714 void* PostProcessConfigurationComponentManager::ComponentHandle::WLock()
715 {
716     CORE_ASSERT(manager_);
717     CORE_ASSERT(rLocked_ <= 1 && !wLocked_);
718     wLocked_ = true;
719     return &data_;
720 }
721 
WUnlock()722 void PostProcessConfigurationComponentManager::ComponentHandle::WUnlock()
723 {
724     CORE_ASSERT(manager_);
725     CORE_ASSERT(wLocked_);
726     wLocked_ = false;
727     // update generation etc..
728     generation_++;
729     if (CORE_NS::EntityUtil::IsValid(entity_)) {
730         dirty_ = true;
731         UpdateMetadata();
732         manager_->Updated(entity_);
733     }
734 }
735 
736 // ComponentHandle IPropertyApi
PropertyCount() const737 size_t PostProcessConfigurationComponentManager::ComponentHandle::PropertyCount() const
738 {
739     return manager_->PropertyCount();
740 }
741 
MetaData(size_t index) const742 const Property* PostProcessConfigurationComponentManager::ComponentHandle::MetaData(size_t index) const
743 {
744     return manager_->MetaData(index);
745 }
746 
MetaData() const747 array_view<const Property> PostProcessConfigurationComponentManager::ComponentHandle::MetaData() const
748 {
749     return manager_->MetaData();
750 }
751 
Type() const752 uint64_t PostProcessConfigurationComponentManager::ComponentHandle::Type() const
753 {
754     return manager_->Type();
755 }
756 
Create() const757 IPropertyHandle* PostProcessConfigurationComponentManager::ComponentHandle::Create() const
758 {
759     return new ComponentHandle(manager_, {}, {});
760 }
761 
Clone(const IPropertyHandle * src) const762 IPropertyHandle* PostProcessConfigurationComponentManager::ComponentHandle::Clone(const IPropertyHandle* src) const
763 {
764     if (src) {
765         auto owner = src->Owner();
766         if (owner == this) {
767             auto* h = static_cast<const ComponentHandle*>(src);
768             return new ComponentHandle(h->manager_, {}, h->data_);
769         } else if (owner) {
770             return owner->Clone(src);
771         }
772         return manager_->Clone(src);
773     }
774     return nullptr;
775 }
776 
Release(IPropertyHandle * handle) const777 void PostProcessConfigurationComponentManager::ComponentHandle::Release(IPropertyHandle* handle) const
778 {
779     if (handle) {
780         auto owner = handle->Owner();
781         if (owner == this) {
782             auto* componentHandle = static_cast<ComponentHandle*>(handle);
783             if (auto id = manager_->GetComponentId(componentHandle->entity_);
784                 id != IComponentManager::INVALID_COMPONENT_ID) {
785                 if (manager_->GetData(id) == componentHandle) {
786                     // This is one of the components (bound to an entity) so do nothing
787                     return;
788                 }
789             }
790             delete componentHandle;
791         } else if (owner) {
792             owner->Release(handle);
793         }
794     }
795 }
796 
UpdateMetadata()797 void PostProcessConfigurationComponentManager::ComponentHandle::UpdateMetadata()
798 {
799     if (!manager_->renderHandleManager_) {
800         if (manager_->renderHandleManager_ = GetManager<IRenderHandleComponentManager>(manager_->ecs_);
801             !manager_->renderHandleManager_) {
802             return;
803         }
804     }
805     // resize for all single post processes
806     effectShaders_.resize(data_.postProcesses.size());
807     customProperties_.resize(data_.postProcesses.size());
808     // loop through all post process effects for new shaders
809     // NOTE: could cache shaders and/or check which single post processes are actually changed
810     for (size_t idx = 0; idx < data_.postProcesses.size(); ++idx) {
811         if (effectShaders_[idx] != data_.postProcesses[idx].shader) {
812             effectShaders_[idx] = data_.postProcesses[idx].shader;
813             const auto currentShader = manager_->renderHandleManager_->GetRenderHandleReference(effectShaders_[idx]);
814 
815             auto newPod = make_unique<CustomPropertyPodContainer>(CUSTOM_PROPERTY_POD_CONTAINER_BYTE_SIZE);
816             if (currentShader) {
817                 if (const json::value* metaJson = manager_->shaderManager_.GetMaterialMetadata(currentShader);
818                     metaJson && metaJson->is_array()) {
819                     UpdateCustomPropertyMetadata(*metaJson, *newPod);
820                 }
821             }
822 
823             auto& properties = customProperties_[idx];
824             if (properties) {
825                 newPod->CopyValues(*properties);
826             }
827             properties = BASE_NS::move(newPod);
828         }
829 
830         // re-fetch the property always
831         data_.postProcesses[idx].customProperties = customProperties_[idx].get();
832     }
833 }
834 
835 //
836 
IPostProcessConfigurationComponentManagerInstance(IEcs & ecs)837 IComponentManager* IPostProcessConfigurationComponentManagerInstance(IEcs& ecs)
838 {
839     return new PostProcessConfigurationComponentManager(ecs);
840 }
841 
IPostProcessConfigurationComponentManagerDestroy(IComponentManager * instance)842 void IPostProcessConfigurationComponentManagerDestroy(IComponentManager* instance)
843 {
844     delete static_cast<PostProcessConfigurationComponentManager*>(instance);
845 }
846 
847 CORE3D_END_NAMESPACE()
848