1 /*
2 * Copyright (c) 2022 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 #ifndef CORE3D_UTIL_PROPERTY_UTIL_H
17 #define CORE3D_UTIL_PROPERTY_UTIL_H
18
19 #include <3d/namespace.h>
20 #include <base/containers/string.h>
21 #include <base/containers/vector.h>
22 #include <core/ecs/entity_reference.h>
23 #include <core/json/json.h>
24 #include <core/property/intf_property_api.h>
25 #include <core/property/intf_property_handle.h>
26 #include <core/property/property_handle_util.h>
27 #include <core/property/property_types.h>
28
CORE3D_BEGIN_NAMESPACE()29 CORE3D_BEGIN_NAMESPACE()
30 /*
31 * Simple signaller class
32 */
33 class CustomPropertyWriteSignal {
34 public:
35 CustomPropertyWriteSignal() = default;
36 virtual ~CustomPropertyWriteSignal() = default;
37
38 virtual void Signal() = 0;
39 };
40
41 /*
42 * Implements a custom property blob for simple PODs e.g. shader custom shader properties which are stored in a single
43 * byte data.
44 * Supports float -> vec4 with u/i -variants
45 * - Single byte data blob
46 * - Multiple offsets customized properties for that data
47 * - Can only hold simple data within a single byte-blob
48 *
49 * NOTE: One must use Reserve(propertyCount) before adding properties
50 */
51 class CustomPropertyPodContainer final : public CORE_NS::IPropertyHandle, CORE_NS::IPropertyApi {
52 public:
53 /* Reserve a predefined byte size to hold the property data */
54 CustomPropertyPodContainer(CustomPropertyWriteSignal& writeSignal, size_t reserveByteSize);
55
56 ~CustomPropertyPodContainer() override = default;
57
58 CustomPropertyPodContainer(const CustomPropertyPodContainer& other) = delete;
59 CustomPropertyPodContainer(CustomPropertyPodContainer&& other) = delete;
60 CustomPropertyPodContainer& operator=(const CustomPropertyPodContainer& other) = delete;
61 CustomPropertyPodContainer& operator=(CustomPropertyPodContainer&& other) = delete;
62
63 // IPropertyHandle
64 const CORE_NS::IPropertyApi* Owner() const override;
65 size_t Size() const override;
66 const void* RLock() const override;
67 void RUnlock() const override;
68 void* WLock() override;
69 void WUnlock() override;
70
71 // IPropertyApi
72 size_t PropertyCount() const override;
73 const CORE_NS::Property* MetaData(size_t index) const override;
74 BASE_NS::array_view<const CORE_NS::Property> MetaData() const override;
75 uint64_t Type() const override;
76 CORE_NS::IPropertyHandle* Create() const override;
77 CORE_NS::IPropertyHandle* Clone(const CORE_NS::IPropertyHandle* src) const override;
78 void Release(CORE_NS::IPropertyHandle* handle) const override;
79
80 // Reset, to remove old properties
81 void Reset();
82 // Reserve before adding any properties
83 void ReservePropertyCount(size_t propertyCount);
84
85 void AddOffsetProperty(BASE_NS::string_view propertyName, BASE_NS::string_view displayName, uintptr_t offset,
86 const CORE_NS::PropertyTypeDecl& typeDecl);
87 void AddOffsetProperty(BASE_NS::string_view propertyName, BASE_NS::string_view displayName, uintptr_t offset,
88 const CORE_NS::PropertyTypeDecl& typeDecl, BASE_NS::array_view<const uint8_t> data);
89 bool SetValue(BASE_NS::string_view propertyName, BASE_NS::array_view<const uint8_t> data);
90 bool SetValue(size_t byteOffset, BASE_NS::array_view<const uint8_t> data);
91 BASE_NS::array_view<const uint8_t> GetValue(BASE_NS::string_view name) const;
92 // byte size of the data container
93 size_t GetByteSize() const;
94
95 void CopyValues(const CustomPropertyPodContainer& other);
96
97 // Uses property handle util
98 template<typename T>
SetValue(BASE_NS::string_view propertyName,T && propertyValue)99 bool SetValue(BASE_NS::string_view propertyName, T&& propertyValue)
100 {
101 return CORE_NS::SetPropertyValue(*this, propertyName, BASE_NS::forward<T>(propertyValue));
102 }
103 template<typename T>
GetValue(BASE_NS::string_view propertyName)104 T GetValue(BASE_NS::string_view propertyName)
105 {
106 return CORE_NS::GetPropertyValue<T>(*this, propertyName);
107 }
108 void UpdateSignal(CustomPropertyWriteSignal& writeSignal);
109
110 private:
111 struct Strings {
112 BASE_NS::string name;
113 BASE_NS::string displayName;
114 };
115
116 // signal when value is written
117 CustomPropertyWriteSignal* writeSignal_;
118 BASE_NS::vector<Strings> metaStrings_;
119 BASE_NS::vector<CORE_NS::Property> metaData_;
120 BASE_NS::vector<uint8_t> data_;
121
122 size_t reservePropertyCount_ { 0 };
123 };
124
125 /*
126 * CustomPropertyDataHelper
127 */
128 class CustomPropertyPodHelper final {
129 public:
130 CustomPropertyPodHelper() = default;
131 ~CustomPropertyPodHelper() = default;
132
133 static CORE_NS::PropertyTypeDecl GetPropertyTypeDeclaration(const BASE_NS::string_view type);
134 static size_t GetPropertyTypeAlignment(const CORE_NS::PropertyTypeDecl& propertyType);
135 static void SetCustomPropertyBlobValue(const CORE_NS::PropertyTypeDecl& propertyType,
136 const CORE_NS::json::value* value, CustomPropertyPodContainer& customProperties, const size_t offset);
137 };
138
139 /*
140 * Implements a custom binding properties.
141 *
142 * NOTE: One must use Reserve(propertyCount) before adding properties
143 */
144 class CustomPropertyBindingContainer final : public CORE_NS::IPropertyHandle, CORE_NS::IPropertyApi {
145 public:
146 explicit CustomPropertyBindingContainer(CustomPropertyWriteSignal& writeSignal);
147 ~CustomPropertyBindingContainer() override;
148
149 CustomPropertyBindingContainer(const CustomPropertyBindingContainer& other) = delete;
150 CustomPropertyBindingContainer(CustomPropertyBindingContainer&& other) noexcept;
151 CustomPropertyBindingContainer& operator=(const CustomPropertyBindingContainer& other) = delete;
152 CustomPropertyBindingContainer& operator=(CustomPropertyBindingContainer&& other) noexcept;
153
154 // IPropertyHandle
155 const CORE_NS::IPropertyApi* Owner() const override;
156 size_t Size() const override;
157 const void* RLock() const override;
158 void RUnlock() const override;
159 void* WLock() override;
160 void WUnlock() override;
161
162 // IPropertyApi
163 size_t PropertyCount() const override;
164 const CORE_NS::Property* MetaData(size_t index) const override;
165 BASE_NS::array_view<const CORE_NS::Property> MetaData() const override;
166 uint64_t Type() const override;
167 CORE_NS::IPropertyHandle* Create() const override;
168 CORE_NS::IPropertyHandle* Clone(const CORE_NS::IPropertyHandle* src) const override;
169 void Release(CORE_NS::IPropertyHandle* handle) const override;
170
171 // Reserve before adding any properties
172 void ReservePropertyCount(size_t propertyCount);
173
174 void AddOffsetProperty(const BASE_NS::string_view propertyName, const BASE_NS::string_view displayName,
175 const uintptr_t offset, const CORE_NS::PropertyTypeDecl& typeDecl);
176 // byte size of the data container
177 size_t GetByteSize() const;
178
179 // Uses property handle util
180 template<typename T>
SetValue(const BASE_NS::string_view propertyName,T && propertyValue)181 bool SetValue(const BASE_NS::string_view propertyName, T&& propertyValue)
182 {
183 return CORE_NS::SetPropertyValue<T>(*this, propertyName, propertyValue);
184 }
185 template<typename T>
GetValue(const BASE_NS::string_view propertyName)186 T GetValue(const BASE_NS::string_view propertyName) const
187 {
188 return CORE_NS::GetPropertyValue<T>(*this, propertyName);
189 }
190 template<typename T>
GetValue(size_t index)191 T GetValue(size_t index) const
192 {
193 // the casting type needs to be known
194 constexpr size_t ptrSize = sizeof(CORE_NS::EntityReference);
195 static_assert(sizeof(T) == ptrSize);
196 if ((index < metaData_.size())) {
197 const auto& meta = metaData_[index];
198 CORE_ASSERT(meta.offset < data_.size_in_bytes());
199 if (void* ptr = (void*)(data_.data() + meta.offset); ptr) {
200 return *((T*)(ptr));
201 }
202 }
203 return {};
204 }
205
206 void CopyValues(const CustomPropertyBindingContainer& other);
207
208 void UpdateSignal(CustomPropertyWriteSignal& writeSignal);
209
210 private:
211 // signal when value is written
212 CustomPropertyWriteSignal* writeSignal_;
213
214 struct Strings {
215 BASE_NS::string name;
216 BASE_NS::string displayName;
217 };
218 BASE_NS::vector<Strings> metaStrings_;
219 BASE_NS::vector<CORE_NS::Property> metaData_;
220 BASE_NS::vector<uint8_t> data_;
221 size_t reservePropertyCount_ { 0 };
222 };
223
224 /*
225 * CustomBindingPropertyHelper
226 */
227 namespace CustomPropertyBindingHelper {
228 CORE_NS::PropertyTypeDecl GetPropertyTypeDeclaration(const BASE_NS::string_view type);
229 size_t GetPropertyTypeAlignment(const CORE_NS::PropertyTypeDecl& propertyType);
230 } // namespace CustomPropertyBindingHelper
231 CORE3D_END_NAMESPACE()
232
233 #endif // CORE3D_UTIL_PROPERTY_UTIL_H
234