• 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 "util/property_util.h"
17 
18 #include <cinttypes>
19 
20 #include <base/math/vector.h>
21 #include <core/log.h>
22 #include <core/property/intf_property_handle.h>
23 #include <core/property/property_types.h>
24 #include <core/property_tools/core_metadata.inl>
25 
26 #include "util/component_util_functions.h"
27 #include "util/json_util.h"
28 #include "util/string_util.h"
29 
30 CORE_BEGIN_NAMESPACE()
31 static constexpr inline bool operator==(const Property& lhs, const Property& rhs) noexcept
32 {
33     return (lhs.type == rhs.type) && (lhs.hash == rhs.hash) && (lhs.name == rhs.name);
34 }
35 CORE_END_NAMESPACE()
36 
37 CORE3D_BEGIN_NAMESPACE()
38 using namespace BASE_NS;
39 using namespace CORE_NS;
40 
41 namespace {
42 constexpr size_t ENTITY_REFERENCE_BYTE_SIZE = sizeof(EntityReference);
43 
GetPropertyTypeByteSize(const PropertyTypeDecl & typeDecl)44 uint32_t GetPropertyTypeByteSize(const PropertyTypeDecl& typeDecl)
45 {
46     uint32_t byteSize = 0; // zero means that un-supported property type
47     switch (typeDecl) {
48         case PropertyType::UINT32_T:
49         case PropertyType::INT32_T:
50         case PropertyType::FLOAT_T:
51         case PropertyType::BOOL_T:
52             byteSize = sizeof(uint32_t);
53             break;
54         case PropertyType::UVEC2_T:
55         case PropertyType::IVEC2_T:
56         case PropertyType::VEC2_T:
57             byteSize = sizeof(Math::UVec2);
58             break;
59         case PropertyType::UVEC3_T:
60         case PropertyType::IVEC3_T:
61         case PropertyType::VEC3_T:
62             byteSize = sizeof(Math::UVec3);
63             break;
64         case PropertyType::UVEC4_T:
65         case PropertyType::IVEC4_T:
66         case PropertyType::VEC4_T:
67             byteSize = sizeof(Math::UVec4);
68             break;
69         case PropertyType::MAT3X3_T:
70             byteSize = sizeof(Math::Mat3X3);
71             break;
72         case PropertyType::MAT4X4_T:
73             byteSize = sizeof(Math::Mat4X4);
74             break;
75     }
76     return byteSize;
77 }
78 
GetMetaData(const PropertyTypeDecl & typeDecl)79 constexpr MetaData GetMetaData(const PropertyTypeDecl& typeDecl)
80 {
81     switch (typeDecl) {
82         case PropertyType::UINT32_T:
83             return PropertyType::MetaDataFrom<uint32_t>();
84         case PropertyType::INT32_T:
85             return PropertyType::MetaDataFrom<int32_t>();
86         case PropertyType::FLOAT_T:
87             return PropertyType::MetaDataFrom<float>();
88 
89         case PropertyType::BOOL_T:
90             return PropertyType::MetaDataFrom<bool>();
91 
92         case PropertyType::UVEC2_T:
93             return PropertyType::MetaDataFrom<Math::UVec2>();
94         case PropertyType::IVEC2_T:
95             return PropertyType::MetaDataFrom<Math::IVec2>();
96         case PropertyType::VEC2_T:
97             return PropertyType::MetaDataFrom<Math::Vec2>();
98 
99         case PropertyType::UVEC3_T:
100             return PropertyType::MetaDataFrom<Math::UVec3>();
101         case PropertyType::IVEC3_T:
102             return PropertyType::MetaDataFrom<Math::IVec3>();
103         case PropertyType::VEC3_T:
104             return PropertyType::MetaDataFrom<Math::Vec3>();
105 
106         case PropertyType::UVEC4_T:
107             return PropertyType::MetaDataFrom<Math::UVec4>();
108         case PropertyType::IVEC4_T:
109             return PropertyType::MetaDataFrom<Math::IVec4>();
110         case PropertyType::VEC4_T:
111             return PropertyType::MetaDataFrom<Math::Vec4>();
112 
113         case PropertyType::MAT3X3_T:
114             return PropertyType::MetaDataFrom<Math::Mat3X3>();
115         case PropertyType::MAT4X4_T:
116             return PropertyType::MetaDataFrom<Math::Mat4X4>();
117     }
118     return {};
119 }
120 
121 template<typename T>
SafeFromJsonValue(const json::value * value,T & val)122 inline void SafeFromJsonValue(const json::value* value, T& val)
123 {
124     if (value) {
125         FromJson(*value, val);
126     }
127 }
128 
129 template<typename T>
DestroyHelper(T & t)130 inline void DestroyHelper(T& t)
131 {
132     {
133         t.~T();
134     }
135 }
136 } // namespace
137 
CustomPropertyPodContainer(CustomPropertyWriteSignal & writeSignal,size_t reserveByteSize)138 CustomPropertyPodContainer::CustomPropertyPodContainer(CustomPropertyWriteSignal& writeSignal, size_t reserveByteSize)
139     : writeSignal_(&writeSignal)
140 {
141     data_.reserve(reserveByteSize);
142 }
143 
PropertyCount() const144 size_t CustomPropertyPodContainer::PropertyCount() const
145 {
146     return metaData_.size();
147 }
148 
MetaData(size_t index) const149 const Property* CustomPropertyPodContainer::MetaData(size_t index) const
150 {
151     if (index < metaData_.size()) {
152         return &metaData_[index];
153     }
154 
155     return nullptr;
156 }
157 
MetaData() const158 array_view<const Property> CustomPropertyPodContainer::MetaData() const
159 {
160     return { metaData_ };
161 }
162 
Type() const163 uint64_t CustomPropertyPodContainer::Type() const
164 {
165     return 0;
166 }
167 
Create() const168 IPropertyHandle* CustomPropertyPodContainer::Create() const
169 {
170     return nullptr;
171 }
172 
Clone(const IPropertyHandle *) const173 IPropertyHandle* CustomPropertyPodContainer::Clone(const IPropertyHandle* /* src */) const
174 {
175     return nullptr;
176 }
177 
Release(IPropertyHandle *) const178 void CustomPropertyPodContainer::Release(IPropertyHandle* /* handle */) const {}
179 
Reset()180 void CustomPropertyPodContainer::Reset()
181 {
182     metaStrings_.clear();
183     metaData_.clear();
184     data_.clear();
185 }
186 
ReservePropertyCount(size_t propertyCount)187 void CustomPropertyPodContainer::ReservePropertyCount(size_t propertyCount)
188 {
189     reservePropertyCount_ = propertyCount;
190     metaStrings_.reserve(reservePropertyCount_);
191     metaData_.reserve(reservePropertyCount_);
192 }
193 
194 // CustomProperties IPropertyHandle
Owner() const195 const IPropertyApi* CustomPropertyPodContainer::Owner() const
196 {
197     return this;
198 }
199 
Size() const200 size_t CustomPropertyPodContainer::Size() const
201 {
202     return data_.size();
203 }
204 
RLock() const205 const void* CustomPropertyPodContainer::RLock() const
206 {
207     return data_.data();
208 }
209 
RUnlock() const210 void CustomPropertyPodContainer::RUnlock() const {}
211 
WLock()212 void* CustomPropertyPodContainer::WLock()
213 {
214     return data_.data();
215 }
216 
WUnlock()217 void CustomPropertyPodContainer::WUnlock()
218 {
219     // signal that properties have been written
220     writeSignal_->Signal();
221 }
222 
223 //
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)224 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
225     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
226 {
227     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
228     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
229     if ((byteSize > 0) && reserved) {
230         metaStrings_.push_back({ string { propertyName }, string { displayName } });
231         const auto& strings = metaStrings_.back();
232         const Property meta {
233             strings.name,                                        // name
234             FNV1aHash(strings.name.data(), strings.name.size()), // hash
235             typeDecl,                                            // type
236             1U,                                                  // count
237             byteSize,                                            // size
238             offset,                                              // offset
239             strings.displayName,                                 // displayName
240             0U,                                                  // flags
241             GetMetaData(typeDecl),                               // metaData
242         };
243         metaData_.push_back(meta);
244         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
245     } else {
246         CORE_LOG_W("unsupported property addition for custom property POD container");
247     }
248 }
249 
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl,const array_view<const uint8_t> data)250 void CustomPropertyPodContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
251     const uintptr_t offset, const PropertyTypeDecl& typeDecl, const array_view<const uint8_t> data)
252 {
253     const size_t byteSize = GetPropertyTypeByteSize(typeDecl);
254     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
255     if ((byteSize > 0) && reserved) {
256         metaStrings_.push_back({ string { propertyName }, string { displayName } });
257         const auto& strings = metaStrings_.back();
258         const Property meta {
259             strings.name,                                        // name
260             FNV1aHash(strings.name.data(), strings.name.size()), // hash
261             typeDecl,                                            // type
262             1U,                                                  // count
263             byteSize,                                            // size
264             offset,                                              // offset
265             strings.displayName,                                 // displayName
266             0U,                                                  // flags
267             GetMetaData(typeDecl),                               // metaData
268         };
269         metaData_.push_back(meta);
270         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
271         if (data.size_bytes() == byteSize) {
272             CloneData(data_.data() + offset, data_.size_in_bytes() - offset, data.data(), data.size_bytes());
273         }
274     } else {
275         CORE_LOG_W("unsupported property addition for custom property POD container");
276     }
277 }
278 
SetValue(const string_view propertyName,const array_view<const uint8_t> data)279 bool CustomPropertyPodContainer::SetValue(const string_view propertyName, const array_view<const uint8_t> data)
280 {
281     for (const auto& metaRef : metaData_) {
282         if ((metaRef.name == propertyName) && (metaRef.size == data.size_bytes())) {
283             return SetValue(metaRef.offset, data);
284         }
285     }
286     return false;
287 }
288 
SetValue(const size_t byteOffset,const array_view<const uint8_t> data)289 bool CustomPropertyPodContainer::SetValue(const size_t byteOffset, const array_view<const uint8_t> data)
290 {
291     return CloneData(data_.data() + byteOffset,
292         (byteOffset < data_.size_in_bytes()) ? (data_.size_in_bytes() - byteOffset) : 0U, data.data(),
293         data.size_bytes());
294 }
295 
GetValue(const string_view propertyName) const296 array_view<const uint8_t> CustomPropertyPodContainer::GetValue(const string_view propertyName) const
297 {
298     for (const auto& metaRef : metaData_) {
299         if (metaRef.name == propertyName) {
300             const size_t endData = metaRef.offset + metaRef.size;
301             if (endData <= data_.size_in_bytes()) {
302                 return { data_.data() + metaRef.offset, metaRef.size };
303             }
304         }
305     }
306     return {};
307 }
308 
GetByteSize() const309 size_t CustomPropertyPodContainer::GetByteSize() const
310 {
311     return data_.size_in_bytes();
312 }
313 
CopyValues(const CustomPropertyPodContainer & other)314 void CustomPropertyPodContainer::CopyValues(const CustomPropertyPodContainer& other)
315 {
316     // copy values with matching type and name
317     for (const auto& otherProperty : other.MetaData()) {
318         if (auto pos = std::find(metaData_.cbegin(), metaData_.cend(), otherProperty); pos != metaData_.cend()) {
319             SetValue(pos->offset, other.GetValue(otherProperty.name));
320         }
321     }
322 }
323 
UpdateSignal(CustomPropertyWriteSignal & writeSignal)324 void CustomPropertyPodContainer::UpdateSignal(CustomPropertyWriteSignal& writeSignal)
325 {
326     writeSignal_ = &writeSignal;
327 }
328 
329 //
GetPropertyTypeDeclaration(const string_view type)330 PropertyTypeDecl CustomPropertyPodHelper::GetPropertyTypeDeclaration(const string_view type)
331 {
332     if (type == "vec4") {
333         return PropertyType::VEC4_T;
334     } else if (type == "uvec4") {
335         return PropertyType::UVEC4_T;
336     } else if (type == "ivec4") {
337         return PropertyType::IVEC4_T;
338     } else if (type == "vec3") {
339         return PropertyType::VEC3_T;
340     } else if (type == "uvec3") {
341         return PropertyType::UVEC3_T;
342     } else if (type == "ivec3") {
343         return PropertyType::IVEC3_T;
344     } else if (type == "vec2") {
345         return PropertyType::VEC2_T;
346     } else if (type == "uvec2") {
347         return PropertyType::UVEC2_T;
348     } else if (type == "ivec2") {
349         return PropertyType::IVEC2_T;
350     } else if (type == "float") {
351         return PropertyType::FLOAT_T;
352     } else if (type == "uint") {
353         return PropertyType::UINT32_T;
354     } else if (type == "int") {
355         return PropertyType::INT32_T;
356     } else if (type == "bool") {
357         return PropertyType::BOOL_T;
358     } else if (type == "mat3x3") {
359         return PropertyType::MAT3X3_T;
360     } else if (type == "mat4x4") {
361         return PropertyType::MAT4X4_T;
362     } else {
363         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only int, uint, float, bool, and XvecX variants, and "
364                    "mat3x3 and mat4x4 are supported");
365     }
366     // NOTE: does not handle invalid types
367     return PropertyType::INVALID;
368 }
369 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)370 size_t CustomPropertyPodHelper::GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
371 {
372     size_t align = 1U;
373     static_assert(sizeof(float) == sizeof(uint32_t) && sizeof(float) == sizeof(int32_t));
374     switch (propertyType) {
375         case PropertyType::FLOAT_T:
376             [[fallthrough]];
377         case PropertyType::UINT32_T:
378             [[fallthrough]];
379         case PropertyType::INT32_T:
380             [[fallthrough]];
381         case PropertyType::BOOL_T:
382             align = sizeof(float);
383             break;
384         case PropertyType::VEC2_T:
385             [[fallthrough]];
386         case PropertyType::UVEC2_T:
387             [[fallthrough]];
388         case PropertyType::IVEC2_T:
389             align = sizeof(float) * 2U;
390             break;
391         case PropertyType::VEC3_T:
392             [[fallthrough]];
393         case PropertyType::UVEC3_T:
394             [[fallthrough]];
395         case PropertyType::IVEC3_T:
396             [[fallthrough]];
397         case PropertyType::VEC4_T:
398             [[fallthrough]];
399         case PropertyType::UVEC4_T:
400             [[fallthrough]];
401         case PropertyType::IVEC4_T:
402             [[fallthrough]];
403         case PropertyType::MAT3X3_T:
404             [[fallthrough]];
405         case PropertyType::MAT4X4_T:
406             align = sizeof(float) * 4U;
407             break;
408     }
409     return align;
410 }
411 
SetCustomPropertyBlobValue(const PropertyTypeDecl & propertyType,const json::value * value,CustomPropertyPodContainer & customProperties,const size_t offset)412 void CustomPropertyPodHelper::SetCustomPropertyBlobValue(const PropertyTypeDecl& propertyType, const json::value* value,
413     CustomPropertyPodContainer& customProperties, const size_t offset)
414 {
415     if (propertyType == PropertyType::VEC4_T) {
416         Math::Vec4 val;
417         SafeFromJsonValue(value, val);
418         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
419     } else if (propertyType == PropertyType::UVEC4_T) {
420         Math::UVec4 val;
421         SafeFromJsonValue(value, val);
422         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
423     } else if (propertyType == PropertyType::IVEC4_T) {
424         Math::IVec4 val;
425         SafeFromJsonValue(value, val);
426         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec4) });
427     } else if (propertyType == PropertyType::VEC3_T) {
428         Math::Vec3 val;
429         SafeFromJsonValue(value, val);
430         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
431     } else if (propertyType == PropertyType::UVEC3_T) {
432         Math::UVec3 val;
433         SafeFromJsonValue(value, val);
434         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
435     } else if (propertyType == PropertyType::IVEC3_T) {
436         Math::IVec3 val;
437         SafeFromJsonValue(value, val);
438         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec3) });
439     } else if (propertyType == PropertyType::VEC2_T) {
440         Math::Vec2 val;
441         SafeFromJsonValue(value, val);
442         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
443     } else if (propertyType == PropertyType::UVEC2_T) {
444         Math::UVec2 val;
445         SafeFromJsonValue(value, val);
446         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
447     } else if (propertyType == PropertyType::IVEC2_T) {
448         Math::IVec2 val;
449         SafeFromJsonValue(value, val);
450         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Vec2) });
451     } else if (propertyType == PropertyType::FLOAT_T) {
452         float val {};
453         SafeFromJsonValue(value, val);
454         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(float) });
455     } else if (propertyType == PropertyType::UINT32_T) {
456         uint32_t val {};
457         SafeFromJsonValue(value, val);
458         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(uint32_t) });
459     } else if (propertyType == PropertyType::INT32_T) {
460         int32_t val {};
461         SafeFromJsonValue(value, val);
462         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(int32_t) });
463     } else if (propertyType == PropertyType::BOOL_T) {
464         bool tmpVal {};
465         SafeFromJsonValue(value, tmpVal);
466         uint32_t val = tmpVal;
467         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(uint32_t) });
468     } else if (propertyType == PropertyType::MAT3X3_T) {
469         Math::Mat3X3 val;
470         SafeFromJsonValue(value, val);
471         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat3X3) });
472     } else if (propertyType == PropertyType::MAT4X4_T) {
473         Math::Mat4X4 val;
474         SafeFromJsonValue(value, val);
475         customProperties.SetValue(offset, array_view { reinterpret_cast<uint8_t*>(&val), sizeof(Math::Mat4X4) });
476     } else {
477         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only int, uint, float, and XvecX variants supported");
478     }
479     // NOTE: does not handle invalid types
480 }
481 
482 // bindings
483 
CustomPropertyBindingContainer(CustomPropertyWriteSignal & writeSignal)484 CustomPropertyBindingContainer::CustomPropertyBindingContainer(CustomPropertyWriteSignal& writeSignal)
485     : writeSignal_(&writeSignal)
486 {}
487 
~CustomPropertyBindingContainer()488 CustomPropertyBindingContainer::~CustomPropertyBindingContainer()
489 {
490     if (!data_.empty()) {
491         CORE_ASSERT((metaData_.size() * ENTITY_REFERENCE_BYTE_SIZE) == data_.size());
492         for (size_t idx = 0; idx < metaData_.size(); ++idx) {
493             const auto& meta = metaData_[idx];
494             CORE_ASSERT(meta.offset < data_.size_in_bytes());
495             switch (meta.type) {
496                 case PropertyType::ENTITY_REFERENCE_T: {
497                     CORE_ASSERT(meta.size == ENTITY_REFERENCE_BYTE_SIZE);
498                     if (EntityReference* resource = (EntityReference*)(data_.data() + meta.offset); resource) {
499                         DestroyHelper(*resource);
500                     }
501                 }
502                     break;
503                 default: {
504                     CORE_LOG_E("custom property binding destruction error");
505                 }
506                     break;
507             }
508         }
509     }
510 }
511 
PropertyCount() const512 size_t CustomPropertyBindingContainer::PropertyCount() const
513 {
514     return metaData_.size();
515 }
516 
MetaData(size_t index) const517 const Property* CustomPropertyBindingContainer::MetaData(size_t index) const
518 {
519     if (index < metaData_.size()) {
520         return &metaData_[index];
521     }
522 
523     return nullptr;
524 }
525 
MetaData() const526 array_view<const Property> CustomPropertyBindingContainer::MetaData() const
527 {
528     return { metaData_ };
529 }
530 
Type() const531 uint64_t CustomPropertyBindingContainer::Type() const
532 {
533     return 0;
534 }
535 
Create() const536 IPropertyHandle* CustomPropertyBindingContainer::Create() const
537 {
538     return nullptr;
539 }
540 
Clone(const IPropertyHandle * src) const541 IPropertyHandle* CustomPropertyBindingContainer::Clone(const IPropertyHandle* src) const
542 {
543     return nullptr;
544 }
545 
Release(IPropertyHandle * handle) const546 void CustomPropertyBindingContainer::Release(IPropertyHandle* handle) const {}
547 
ReservePropertyCount(size_t propertyCount)548 void CustomPropertyBindingContainer::ReservePropertyCount(size_t propertyCount)
549 {
550     reservePropertyCount_ = propertyCount;
551     metaStrings_.reserve(reservePropertyCount_);
552     metaData_.reserve(reservePropertyCount_);
553     data_.reserve(reservePropertyCount_ * ENTITY_REFERENCE_BYTE_SIZE);
554 }
555 
556 // CustomProperties IPropertyHandle
Owner() const557 const IPropertyApi* CustomPropertyBindingContainer::Owner() const
558 {
559     return this;
560 }
561 
Size() const562 size_t CustomPropertyBindingContainer::Size() const
563 {
564     return data_.size();
565 }
566 
RLock() const567 const void* CustomPropertyBindingContainer::RLock() const
568 {
569     return data_.data();
570 }
571 
RUnlock() const572 void CustomPropertyBindingContainer::RUnlock() const {}
573 
WLock()574 void* CustomPropertyBindingContainer::WLock()
575 {
576     return data_.data();
577 }
578 
WUnlock()579 void CustomPropertyBindingContainer::WUnlock()
580 {
581     // signal that properties have been written
582     writeSignal_->Signal();
583 }
584 
585 //
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)586 void CustomPropertyBindingContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
587     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
588 {
589     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
590     if ((ENTITY_REFERENCE_BYTE_SIZE > 0) && reserved) {
591         metaStrings_.push_back({ string { propertyName }, string { displayName } });
592         const auto& strings = metaStrings_.back();
593         const Property meta {
594             strings.name,                                        // name
595             FNV1aHash(strings.name.data(), strings.name.size()), // hash
596             typeDecl,                                            // type
597             1U,                                                  // count
598             ENTITY_REFERENCE_BYTE_SIZE,                          // size
599             offset,                                              // offset
600             strings.displayName,                                 // displayName
601             0U,                                                  // flags
602             GetMetaData(typeDecl),                               // metaData
603         };
604         metaData_.push_back(meta);
605         // the data has already been reserved in ReservePropertyCount()
606         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
607         switch (meta.type) {
608             case PropertyType::ENTITY_REFERENCE_T: {
609                 new (data_.data() + meta.offset) EntityReference;
610             }
611                 break;
612             default:
613                 break;
614         }
615     } else {
616         CORE_LOG_W("unsupported property addition for custom property binding container");
617     }
618 }
619 
GetByteSize() const620 size_t CustomPropertyBindingContainer::GetByteSize() const
621 {
622     return data_.size_in_bytes();
623 }
624 
CopyValues(const CustomPropertyBindingContainer & other)625 void CustomPropertyBindingContainer::CopyValues(const CustomPropertyBindingContainer& other)
626 {
627     // copy values with matching type and name
628     for (const auto& otherProperty : other.MetaData()) {
629         if (auto pos = std::find(metaData_.cbegin(), metaData_.cend(), otherProperty); pos != metaData_.cend()) {
630             if (const EntityReference ent = other.GetValue<EntityReference>(otherProperty.name); ent) {
631                 SetValue(pos->name, ent);
632             }
633         }
634     }
635 }
636 
UpdateSignal(CustomPropertyWriteSignal & writeSignal)637 void CustomPropertyBindingContainer::UpdateSignal(CustomPropertyWriteSignal& writeSignal)
638 {
639     writeSignal_ = &writeSignal;
640 }
641 
642 // CustomPropertyBindingHelper
643 namespace CustomPropertyBindingHelper {
GetPropertyTypeDeclaration(const string_view type)644 PropertyTypeDecl GetPropertyTypeDeclaration(const string_view type)
645 {
646     if (type == "buffer") {
647         return PropertyType::ENTITY_REFERENCE_T;
648     } else if (type == "image") {
649         return PropertyType::ENTITY_REFERENCE_T;
650     } else if (type == "sampler") {
651         return PropertyType::ENTITY_REFERENCE_T;
652     } else {
653         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only buffer, image, and sampler supported");
654     }
655     // NOTE: does not handle invalid types
656     return PropertyType::INVALID;
657 }
658 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)659 size_t GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
660 {
661     size_t align = 1U;
662     switch (propertyType) {
663         case PropertyType::ENTITY_REFERENCE_T:
664             align = ENTITY_REFERENCE_BYTE_SIZE;
665             break;
666         default:
667             break;
668     }
669     return align;
670 }
671 } // namespace CustomPropertyBindingHelper
672 
673 CORE3D_END_NAMESPACE()
674