cesium-native 0.64.0
Loading...
Searching...
No Matches
PropertyAttributeView.h
1#pragma once
2
3#include <CesiumGltf/Class.h>
4#include <CesiumGltf/ClassProperty.h>
5#include <CesiumGltf/ExtensionModelExtStructuralMetadata.h>
6#include <CesiumGltf/Model.h>
7#include <CesiumGltf/PropertyAttribute.h>
8#include <CesiumGltf/PropertyAttributePropertyView.h>
9
10namespace CesiumGltf {
40
51
63
73public:
82 const Model& model,
83 const PropertyAttribute& propertyAttribute) noexcept;
84
91 PropertyAttributeViewStatus status() const noexcept { return this->_status; }
92
97 const std::optional<std::string>& name() const noexcept {
98 return _pPropertyAttribute->name;
99 }
100
107 const Class* getClass() const noexcept { return _pClass; }
108
117 const ClassProperty* getClassProperty(const std::string& propertyId) const;
118
143 template <typename T, bool Normalized = false>
145 const MeshPrimitive& primitive,
146 const std::string& propertyId) const {
147 if (this->_status != PropertyAttributeViewStatus::Valid) {
150 }
151 const ClassProperty* pClassProperty = getClassProperty(propertyId);
152 if (!pClassProperty) {
155 }
156
157 if constexpr (
162 }
163
164 return getPropertyViewImpl<T, Normalized>(
165 primitive,
166 propertyId,
167 *pClassProperty);
168 }
169
191 template <typename Callback>
193 const MeshPrimitive& primitive,
194 const std::string& propertyId,
195 Callback&& callback) const {
196 if (this->_status != PropertyAttributeViewStatus::Valid) {
197 callback(
198 propertyId,
201 ErrorInvalidPropertyAttribute));
202 return;
203 }
204
205 const ClassProperty* pClassProperty = getClassProperty(propertyId);
206 if (!pClassProperty) {
207 callback(
208 propertyId,
211 return;
212 }
213
214 if (pClassProperty->array) {
215 callback(
216 propertyId,
219 return;
220 }
221
222 PropertyType type = convertStringToPropertyType(pClassProperty->type);
224 if (pClassProperty->componentType) {
225 componentType =
227 }
228
229 bool normalized = pClassProperty->normalized;
230 if (normalized && !isPropertyComponentTypeInteger(componentType)) {
231 callback(
232 propertyId,
235 return;
236 }
237
238 if (type == PropertyType::Scalar) {
239 if (normalized) {
240 getScalarPropertyViewImpl<Callback, true>(
241 primitive,
242 propertyId,
243 *pClassProperty,
244 componentType,
245 std::forward<Callback>(callback));
246 } else {
247 getScalarPropertyViewImpl<Callback, false>(
248 primitive,
249 propertyId,
250 *pClassProperty,
251 componentType,
252 std::forward<Callback>(callback));
253 }
254 return;
255 }
256
257 if (isPropertyTypeVecN(type)) {
258 if (normalized) {
259 getVecNPropertyViewImpl<Callback, true>(
260 primitive,
261 propertyId,
262 *pClassProperty,
263 type,
264 componentType,
265 std::forward<Callback>(callback));
266 } else {
267 getVecNPropertyViewImpl<Callback, false>(
268 primitive,
269 propertyId,
270 *pClassProperty,
271 type,
272 componentType,
273 std::forward<Callback>(callback));
274 }
275 return;
276 }
277
278 if (isPropertyTypeMatN(type)) {
279 if (normalized) {
280 getMatNPropertyViewImpl<Callback, true>(
281 primitive,
282 propertyId,
283 *pClassProperty,
284 type,
285 componentType,
286 std::forward<Callback>(callback));
287 } else {
288 getMatNPropertyViewImpl<Callback, false>(
289 primitive,
290 propertyId,
291 *pClassProperty,
292 type,
293 componentType,
294 std::forward<Callback>(callback));
295 }
296 return;
297 }
298
299 callback(
300 propertyId,
303 return;
304 }
305
327 template <typename Callback>
328 void
329 forEachProperty(const MeshPrimitive& primitive, Callback&& callback) const {
330 for (const auto& property : this->_pClass->properties) {
332 primitive,
333 property.first,
334 std::forward<Callback>(callback));
335 }
336 }
337
338private:
339 template <typename T, bool Normalized>
340 PropertyAttributePropertyView<T, Normalized> getEmptyPropertyViewWithDefault(
341 const MeshPrimitive& primitive,
342 const ClassProperty& classProperty) const {
343 // To make the view have a nonzero size, find the POSITION attribute and get
344 // its accessor count. If it doesn't exist or is somehow erroneous, just
345 // mark the property as nonexistent.
346 if (primitive.attributes.find("POSITION") == primitive.attributes.end()) {
349 }
350
351 const Accessor* pAccessor = _pModel->getSafe<Accessor>(
352 &_pModel->accessors,
353 primitive.attributes.at("POSITION"));
354 if (!pAccessor) {
355 return PropertyAttributePropertyView<T, Normalized>(
357 }
358
359 return PropertyAttributePropertyView<T, Normalized>(
360 classProperty,
361 pAccessor->count);
362 }
363
364 template <typename T, bool Normalized>
365 PropertyAttributePropertyView<T, Normalized> getPropertyViewImpl(
366 const MeshPrimitive& primitive,
367 const std::string& propertyId,
368 const ClassProperty& classProperty) const {
369 auto propertyAttributePropertyIter =
370 _pPropertyAttribute->properties.find(propertyId);
371 if (propertyAttributePropertyIter ==
372 _pPropertyAttribute->properties.end()) {
373 if (!classProperty.required && classProperty.defaultProperty) {
374 // If the property was omitted from the property attribute, it is still
375 // technically valid if it specifies a default value. Try to create a
376 // view that just returns the default value.
377 return getEmptyPropertyViewWithDefault<T, Normalized>(
378 primitive,
379 classProperty);
380 }
381
382 // Otherwise, the property is erroneously nonexistent.
383 return PropertyAttributePropertyView<T, Normalized>(
385 }
386
387 const PropertyAttributeProperty& propertyAttributeProperty =
388 propertyAttributePropertyIter->second;
389
390 return createPropertyView<T, Normalized>(
391 primitive,
392 classProperty,
393 propertyAttributeProperty);
394 }
395
396 template <typename Callback, bool Normalized>
397 void getScalarPropertyViewImpl(
398 const MeshPrimitive& primitive,
399 const std::string& propertyId,
400 const ClassProperty& classProperty,
401 PropertyComponentType componentType,
402 Callback&& callback) const {
403 switch (componentType) {
405 callback(
406 propertyId,
407 getPropertyViewImpl<int8_t, Normalized>(
408 primitive,
409 propertyId,
410 classProperty));
411 return;
413 callback(
414 propertyId,
415 getPropertyViewImpl<uint8_t, Normalized>(
416 primitive,
417 propertyId,
418 classProperty));
419 return;
421 callback(
422 propertyId,
423 getPropertyViewImpl<int16_t, Normalized>(
424 primitive,
425 propertyId,
426 classProperty));
427 return;
429 callback(
430 propertyId,
431 getPropertyViewImpl<uint16_t, Normalized>(
432 primitive,
433 propertyId,
434 classProperty));
435 break;
437 callback(
438 propertyId,
439 getPropertyViewImpl<float, false>(
440 primitive,
441 propertyId,
442 classProperty));
443 break;
444 default:
445 callback(
446 propertyId,
447 PropertyAttributePropertyView<uint8_t>(
449 break;
450 }
451 }
452
453 template <typename Callback, glm::length_t N, bool Normalized>
454 void getVecNPropertyViewImpl(
455 const MeshPrimitive& primitive,
456 const std::string& propertyId,
457 const ClassProperty& classProperty,
458 PropertyComponentType componentType,
459 Callback&& callback) const {
460 switch (componentType) {
462 callback(
463 propertyId,
464 getPropertyViewImpl<glm::vec<N, int8_t>, Normalized>(
465 primitive,
466 propertyId,
467 classProperty));
468 break;
470 callback(
471 propertyId,
472 getPropertyViewImpl<glm::vec<N, uint8_t>, Normalized>(
473 primitive,
474 propertyId,
475 classProperty));
476 break;
478 callback(
479 propertyId,
480 getPropertyViewImpl<glm::vec<N, int16_t>, Normalized>(
481 primitive,
482 propertyId,
483 classProperty));
484 break;
486 callback(
487 propertyId,
488 getPropertyViewImpl<glm::vec<N, uint16_t>, Normalized>(
489 primitive,
490 propertyId,
491 classProperty));
492 break;
494 callback(
495 propertyId,
496 getPropertyViewImpl<glm::vec<N, float>, false>(
497 primitive,
498 propertyId,
499 classProperty));
500 break;
501 default:
502 callback(
503 propertyId,
504 PropertyAttributePropertyView<uint8_t>(
506 break;
507 }
508 }
509
510 template <typename Callback, bool Normalized>
511 void getVecNPropertyViewImpl(
512 const MeshPrimitive& primitive,
513 const std::string& propertyId,
514 const ClassProperty& classProperty,
515 PropertyType type,
516 PropertyComponentType componentType,
517 Callback&& callback) const {
518 const glm::length_t N = getDimensionsFromPropertyType(type);
519 switch (N) {
520 case 2:
521 getVecNPropertyViewImpl<Callback, 2, Normalized>(
522 primitive,
523 propertyId,
524 classProperty,
525 componentType,
526 std::forward<Callback>(callback));
527 break;
528 case 3:
529 getVecNPropertyViewImpl<Callback, 3, Normalized>(
530 primitive,
531 propertyId,
532 classProperty,
533 componentType,
534 std::forward<Callback>(callback));
535 break;
536 case 4:
537 getVecNPropertyViewImpl<Callback, 4, Normalized>(
538 primitive,
539 propertyId,
540 classProperty,
541 componentType,
542 std::forward<Callback>(callback));
543 break;
544 default:
545 callback(
546 propertyId,
547 PropertyAttributePropertyView<uint8_t>(
549 break;
550 }
551 }
552
553 template <typename Callback, glm::length_t N, bool Normalized>
554 void getMatNPropertyViewImpl(
555 const MeshPrimitive& primitive,
556 const std::string& propertyId,
557 const ClassProperty& classProperty,
558 PropertyComponentType componentType,
559 Callback&& callback) const {
560 switch (componentType) {
562 callback(
563 propertyId,
564 getPropertyViewImpl<glm::mat<N, N, int8_t>, Normalized>(
565 primitive,
566 propertyId,
567 classProperty));
568 break;
570 callback(
571 propertyId,
572 getPropertyViewImpl<glm::mat<N, N, uint8_t>, Normalized>(
573 primitive,
574 propertyId,
575 classProperty));
576 break;
578 callback(
579 propertyId,
580 getPropertyViewImpl<glm::mat<N, N, int16_t>, Normalized>(
581 primitive,
582 propertyId,
583 classProperty));
584 break;
586 callback(
587 propertyId,
588 getPropertyViewImpl<glm::mat<N, N, uint16_t>, Normalized>(
589 primitive,
590 propertyId,
591 classProperty));
592 break;
594 callback(
595 propertyId,
596 getPropertyViewImpl<glm::mat<N, N, float>, false>(
597 primitive,
598 propertyId,
599 classProperty));
600 break;
601 default:
602 callback(
603 propertyId,
604 PropertyAttributePropertyView<uint8_t>(
606 break;
607 }
608 }
609
610 template <typename Callback, bool Normalized>
611 void getMatNPropertyViewImpl(
612 const MeshPrimitive& primitive,
613 const std::string& propertyId,
614 const ClassProperty& classProperty,
615 PropertyType type,
616 PropertyComponentType componentType,
617 Callback&& callback) const {
618 glm::length_t N = getDimensionsFromPropertyType(type);
619 switch (N) {
620 case 2:
621 getMatNPropertyViewImpl<Callback, 2, Normalized>(
622 primitive,
623 propertyId,
624 classProperty,
625 componentType,
626 std::forward<Callback>(callback));
627 break;
628 case 3:
629 getMatNPropertyViewImpl<Callback, 3, Normalized>(
630 primitive,
631 propertyId,
632 classProperty,
633 componentType,
634 std::forward<Callback>(callback));
635 break;
636 case 4:
637 getMatNPropertyViewImpl<Callback, 4, Normalized>(
638 primitive,
639 propertyId,
640 classProperty,
641 componentType,
642 std::forward<Callback>(callback));
643 break;
644 default:
645 callback(
646 propertyId,
647 PropertyAttributePropertyView<uint8_t>(
649 break;
650 }
651 }
652
653 template <typename T, bool Normalized>
654 PropertyAttributePropertyView<T, Normalized> createPropertyView(
655 const MeshPrimitive& primitive,
656 const ClassProperty& classProperty,
657 const PropertyAttributeProperty& propertyAttributeProperty) const {
658 const PropertyType type = convertStringToPropertyType(classProperty.type);
659 if (!canRepresentPropertyType<T>(type)) {
660 return PropertyAttributePropertyView<T, Normalized>(
662 }
663
664 const PropertyComponentType componentType =
666 classProperty.componentType.value_or(""));
667 if (TypeToPropertyType<T>::component != componentType) {
668 return PropertyAttributePropertyView<T, Normalized>(
670 }
671
672 if (classProperty.normalized != Normalized) {
673 return PropertyAttributePropertyView<T, Normalized>(
675 }
676
677 if (primitive.attributes.find(propertyAttributeProperty.attribute) ==
678 primitive.attributes.end()) {
679 return PropertyAttributePropertyView<T, Normalized>(
681 }
682
683 const Accessor* pAccessor = _pModel->getSafe<Accessor>(
684 &_pModel->accessors,
685 primitive.attributes.at(propertyAttributeProperty.attribute));
686 if (!pAccessor) {
687 return PropertyAttributePropertyView<T, Normalized>(
689 }
690
691 if (getAccessorTypeAsPropertyType(*pAccessor) != type) {
692 return PropertyAttributePropertyView<T, Normalized>(
694 }
695
697 componentType) {
698 return PropertyAttributePropertyView<T, Normalized>(
699 PropertyAttributePropertyViewStatus::
700 ErrorAccessorComponentTypeMismatch);
701 }
702
703 if (pAccessor->normalized != Normalized) {
704 return PropertyAttributePropertyView<T, Normalized>(
705 PropertyAttributePropertyViewStatus::
706 ErrorAccessorNormalizationMismatch);
707 }
708
709 AccessorView<T> accessorView = AccessorView<T>(*_pModel, *pAccessor);
710 if (accessorView.status() != AccessorViewStatus::Valid) {
711 switch (accessorView.status()) {
713 return PropertyAttributePropertyView<T, Normalized>(
716 return PropertyAttributePropertyView<T, Normalized>(
719 return PropertyAttributePropertyView<T, Normalized>(
722 return PropertyAttributePropertyView<T, Normalized>(
724 default:
725 return PropertyAttributePropertyView<T, Normalized>(
727 }
728 }
729
730 return PropertyAttributePropertyView<T, Normalized>(
731 propertyAttributeProperty,
732 classProperty,
733 accessorView);
734 }
735
736 const Model* _pModel;
737 const PropertyAttribute* _pPropertyAttribute;
738 const Class* _pClass;
739
741};
742
743} // namespace CesiumGltf
Indicates the status of a property attribute property view.
static const int ErrorInvalidBufferView
This property view uses an accessor that does not have a valid buffer view index.
static const int ErrorInvalidBuffer
This property view uses a buffer view that does not have a valid buffer index.
static const int ErrorInvalidAccessor
This property view's attribute does not have a valid accessor index.
static const int ErrorMissingAttribute
This property view was initialized with a primitive that does not contain the specified attribute.
static const int ErrorUnsupportedProperty
This property view is associated with a ClassProperty of an unsupported type.
static const int ErrorAccessorTypeMismatch
This property view's type does not match the type of the accessor it uses.
static const int ErrorInvalidPropertyAttribute
This property view was initialized from an invalid PropertyAttribute.
static const PropertyViewStatusType ErrorAccessorOutOfBounds
This property view uses an accessor that points outside the bounds of its target buffer view.
static const PropertyViewStatusType ErrorBufferViewOutOfBounds
This property view uses a buffer view that points outside the bounds of its target buffer.
A view of the data specified by a PropertyAttributeProperty.
PropertyAttributeView(const Model &model, const PropertyAttribute &propertyAttribute) noexcept
Construct a PropertyAttributeView.
const ClassProperty * getClassProperty(const std::string &propertyId) const
Finds the ClassProperty that describes the type information of the property with the specified id.
PropertyAttributeViewStatus status() const noexcept
Gets the status of this property attribute view.
PropertyAttributePropertyView< T, Normalized > getPropertyView(const MeshPrimitive &primitive, const std::string &propertyId) const
Gets a PropertyAttributePropertyView that views the data of a property stored in the PropertyAttribut...
const std::optional< std::string > & name() const noexcept
Gets the name of the property attribute being viewed. Returns std::nullopt if no name was specified.
void getPropertyView(const MeshPrimitive &primitive, const std::string &propertyId, Callback &&callback) const
Gets a PropertyAttributePropertyView through a callback that accepts a property id and a PropertyAttr...
void forEachProperty(const MeshPrimitive &primitive, Callback &&callback) const
Iterates over each property in the PropertyAttribute with a callback that accepts a property id and a...
const Class * getClass() const noexcept
Gets the Class that this property attribute conforms to.
static const PropertyViewStatusType ErrorTypeMismatch
This property view's type does not match what is specified in ClassProperty::type.
static const PropertyViewStatusType ErrorNonexistentProperty
This property view is trying to view a property that does not exist.
static const PropertyViewStatusType ErrorInvalidNormalization
This property says it is normalized, but it does not have an integer component type.
static const PropertyViewStatusType ErrorNormalizationMismatch
This property view's normalization differs from what is specified in ClassProperty::normalized.
static const PropertyViewStatusType ErrorComponentTypeMismatch
This property view's component type does not match what is specified in ClassProperty::componentType.
Classes for working with glTF models.
PropertyComponentType
The possible types of a property component.
@ Float32
A property component equivalent to a float.
@ Uint16
A property component equivalent to a uint16_t.
@ Int16
A property component equivalent to an int16_t.
@ Uint8
A property component equivalent to a uint8_t.
@ Int8
A property component equivalent to an int8_t.
bool isPropertyTypeVecN(PropertyType type)
Checks if the given PropertyType represents a vector with any number of components.
bool isPropertyComponentTypeInteger(PropertyComponentType componentType)
Checks if the given PropertyComponentType represents an integer value.
PropertyComponentType convertStringToPropertyComponentType(const std::string &str)
Converts a string into a PropertyComponentType.
PropertyAttributeViewStatus
Indicates the status of a property attribute view.
@ Valid
This property attribute view is valid and ready to use.
@ ErrorClassNotFound
The property attribute's specified class could not be found in the extension.
@ ErrorMissingMetadataExtension
The glTF is missing the EXT_structural_metadata extension.
@ ErrorMissingSchema
The glTF EXT_structural_metadata extension doesn't contain a schema.
bool isPropertyTypeMatN(PropertyType type)
Checks if the given PropertyType represents a matrix with any number of components.
PropertyType getAccessorTypeAsPropertyType(const Accessor &accessor)
Attempts to obtain a PropertyType from the type field of the accessor.
bool canRepresentPropertyType(PropertyType type)
Returns whether the type T can represent the given PropertyType.
@ BufferViewTooSmall
The accessor is too large to fit in its bufferView.
@ Valid
This accessor is valid and ready to use.
@ InvalidBufferViewIndex
The accessor's bufferView index does not refer to a valid bufferView.
@ InvalidBufferIndex
The accessor's bufferView's buffer index does not refer to a valid buffer.
@ BufferTooSmall
The accessor's bufferView is too large to fit in its buffer.
PropertyType convertStringToPropertyType(const std::string &str)
Converts a string into a PropertyType.
PropertyType
The possible types of a property in a PropertyTableView.
@ Scalar
A scalar property, i.e. an integer or floating point value.
glm::length_t getDimensionsFromPropertyType(PropertyType type)
Obtains the number of dimensions in the given PropertyType.
PropertyComponentType getAccessorComponentTypeAsPropertyComponentType(const Accessor &accessor)
Attempts to obtain a PropertyComponentType from the componentType field of the accessor.
This class is not meant to be instantiated directly. Use Accessor instead.
Definition Accessor.h:12
bool normalized
Specifies whether integer values are normalized. Only applicable to SCALAR, VECN, and MATN types with...
std::optional< std::string > componentType
The datatype of the element's components. Only applicable to SCALAR, VECN, and MATN types.
bool array
Whether the property is an array. When count is defined the property is a fixed-length array....
std::string type
The element type.
A class containing a set of properties.
Definition Class.h:17
Check if a C++ type can be represented as an array.
Check if a C++ type can be represented as a boolean property type.
Check if a C++ type can be represented as a string property type.
Geometry to be rendered with the given material.
std::unordered_map< std::string, int32_t > attributes
A plain JSON object, where each key corresponds to a mesh attribute semantic and each value is the in...
std::vector< CesiumGltf::Accessor > accessors
An array of accessors.
Definition ModelSpec.h:51
This class is not meant to be instantiated directly. Use Model instead.
Definition Model.h:14
static const T & getSafe(const std::vector< T > &items, int32_t index)
Safely gets the element with a given index, returning a default instance if the index is outside the ...
Definition Model.h:181
Properties conforming to a class, organized as property values stored in attributes.