• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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                 } break;
502                 default: {
503                     CORE_LOG_E("custom property binding destruction error");
504                 } break;
505             }
506         }
507     }
508 }
509 
PropertyCount() const510 size_t CustomPropertyBindingContainer::PropertyCount() const
511 {
512     return metaData_.size();
513 }
514 
MetaData(size_t index) const515 const Property* CustomPropertyBindingContainer::MetaData(size_t index) const
516 {
517     if (index < metaData_.size()) {
518         return &metaData_[index];
519     }
520 
521     return nullptr;
522 }
523 
MetaData() const524 array_view<const Property> CustomPropertyBindingContainer::MetaData() const
525 {
526     return { metaData_ };
527 }
528 
Type() const529 uint64_t CustomPropertyBindingContainer::Type() const
530 {
531     return 0;
532 }
533 
Create() const534 IPropertyHandle* CustomPropertyBindingContainer::Create() const
535 {
536     return nullptr;
537 }
538 
Clone(const IPropertyHandle * src) const539 IPropertyHandle* CustomPropertyBindingContainer::Clone(const IPropertyHandle* src) const
540 {
541     return nullptr;
542 }
543 
Release(IPropertyHandle * handle) const544 void CustomPropertyBindingContainer::Release(IPropertyHandle* handle) const {}
545 
ReservePropertyCount(size_t propertyCount)546 void CustomPropertyBindingContainer::ReservePropertyCount(size_t propertyCount)
547 {
548     reservePropertyCount_ = propertyCount;
549     metaStrings_.reserve(reservePropertyCount_);
550     metaData_.reserve(reservePropertyCount_);
551     data_.reserve(reservePropertyCount_ * ENTITY_REFERENCE_BYTE_SIZE);
552 }
553 
554 // CustomProperties IPropertyHandle
Owner() const555 const IPropertyApi* CustomPropertyBindingContainer::Owner() const
556 {
557     return this;
558 }
559 
Size() const560 size_t CustomPropertyBindingContainer::Size() const
561 {
562     return data_.size();
563 }
564 
RLock() const565 const void* CustomPropertyBindingContainer::RLock() const
566 {
567     return data_.data();
568 }
569 
RUnlock() const570 void CustomPropertyBindingContainer::RUnlock() const {}
571 
WLock()572 void* CustomPropertyBindingContainer::WLock()
573 {
574     return data_.data();
575 }
576 
WUnlock()577 void CustomPropertyBindingContainer::WUnlock()
578 {
579     // signal that properties have been written
580     writeSignal_->Signal();
581 }
582 
583 //
AddOffsetProperty(const string_view propertyName,const string_view displayName,const uintptr_t offset,const PropertyTypeDecl & typeDecl)584 void CustomPropertyBindingContainer::AddOffsetProperty(const string_view propertyName, const string_view displayName,
585     const uintptr_t offset, const PropertyTypeDecl& typeDecl)
586 {
587     const bool reserved = (metaStrings_.size() < reservePropertyCount_);
588     if ((ENTITY_REFERENCE_BYTE_SIZE > 0) && reserved) {
589         metaStrings_.push_back({ string { propertyName }, string { displayName } });
590         const auto& strings = metaStrings_.back();
591         const Property meta {
592             strings.name,                                        // name
593             FNV1aHash(strings.name.data(), strings.name.size()), // hash
594             typeDecl,                                            // type
595             1U,                                                  // count
596             ENTITY_REFERENCE_BYTE_SIZE,                          // size
597             offset,                                              // offset
598             strings.displayName,                                 // displayName
599             0U,                                                  // flags
600             GetMetaData(typeDecl),                               // metaData
601         };
602         metaData_.push_back(meta);
603         // the data has already been reserved in ReservePropertyCount()
604         data_.resize(Math::max(data_.size(), meta.offset + meta.size));
605         switch (meta.type) {
606             case PropertyType::ENTITY_REFERENCE_T: {
607                 new (data_.data() + meta.offset) EntityReference;
608             } break;
609         }
610     } else {
611         CORE_LOG_W("unsupported property addition for custom property binding container");
612     }
613 }
614 
GetByteSize() const615 size_t CustomPropertyBindingContainer::GetByteSize() const
616 {
617     return data_.size_in_bytes();
618 }
619 
CopyValues(const CustomPropertyBindingContainer & other)620 void CustomPropertyBindingContainer::CopyValues(const CustomPropertyBindingContainer& other)
621 {
622     // copy values with matching type and name
623     for (const auto& otherProperty : other.MetaData()) {
624         if (auto pos = std::find(metaData_.cbegin(), metaData_.cend(), otherProperty); pos != metaData_.cend()) {
625             if (const EntityReference ent = other.GetValue<EntityReference>(otherProperty.name); ent) {
626                 SetValue(pos->name, ent);
627             }
628         }
629     }
630 }
631 
UpdateSignal(CustomPropertyWriteSignal & writeSignal)632 void CustomPropertyBindingContainer::UpdateSignal(CustomPropertyWriteSignal& writeSignal)
633 {
634     writeSignal_ = &writeSignal;
635 }
636 
637 // CustomPropertyBindingHelper
638 namespace CustomPropertyBindingHelper {
GetPropertyTypeDeclaration(const string_view type)639 PropertyTypeDecl GetPropertyTypeDeclaration(const string_view type)
640 {
641     if (type == "buffer") {
642         return PropertyType::ENTITY_REFERENCE_T;
643     } else if (type == "image") {
644         return PropertyType::ENTITY_REFERENCE_T;
645     } else if (type == "sampler") {
646         return PropertyType::ENTITY_REFERENCE_T;
647     } else {
648         CORE_LOG_W("CORE3D_VALIDATION: Invalid property type only buffer, image, and sampler supported");
649     }
650     // NOTE: does not handle invalid types
651     return PropertyType::INVALID;
652 }
653 
GetPropertyTypeAlignment(const PropertyTypeDecl & propertyType)654 size_t GetPropertyTypeAlignment(const PropertyTypeDecl& propertyType)
655 {
656     size_t align = 1U;
657     switch (propertyType) {
658         case PropertyType::ENTITY_REFERENCE_T:
659             align = ENTITY_REFERENCE_BYTE_SIZE;
660             break;
661     }
662     return align;
663 }
664 } // namespace CustomPropertyBindingHelper
665 
666 CORE3D_END_NAMESPACE()
667