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