cesium-native  0.41.0
PropertyAttributeView.h
1 #pragma once
2 
3 #include "CesiumGltf/Class.h"
4 #include "CesiumGltf/ClassProperty.h"
5 #include "CesiumGltf/ExtensionModelExtStructuralMetadata.h"
6 #include "CesiumGltf/PropertyAttribute.h"
7 #include "CesiumGltf/PropertyAttributePropertyView.h"
8 #include "Model.h"
9 
10 namespace CesiumGltf {
22  Valid,
23 
28 
33 
39 };
40 
41 PropertyType getAccessorTypeAsPropertyType(const Accessor& accessor);
42 
43 PropertyComponentType
44 getAccessorComponentTypeAsPropertyComponentType(const Accessor& accessor);
45 
55 public:
64  const Model& model,
65  const PropertyAttribute& propertyAttribute) noexcept;
66 
73  PropertyAttributeViewStatus status() const noexcept { return this->_status; }
74 
79  const std::optional<std::string>& name() const noexcept {
80  return _pPropertyAttribute->name;
81  }
82 
89  const Class* getClass() const noexcept { return _pClass; }
90 
99  const ClassProperty* getClassProperty(const std::string& propertyId) const;
100 
125  template <typename T, bool Normalized = false>
127  const MeshPrimitive& primitive,
128  const std::string& propertyId) const {
129  if (this->_status != PropertyAttributeViewStatus::Valid) {
132  }
133  const ClassProperty* pClassProperty = getClassProperty(propertyId);
134  if (!pClassProperty) {
137  }
138 
139  if constexpr (
144  }
145 
146  return getPropertyViewImpl<T, Normalized>(
147  primitive,
148  propertyId,
149  *pClassProperty);
150  }
151 
172  template <typename Callback>
174  const MeshPrimitive& primitive,
175  const std::string& propertyId,
176  Callback&& callback) const {
177  if (this->_status != PropertyAttributeViewStatus::Valid) {
178  callback(
179  propertyId,
182  ErrorInvalidPropertyAttribute));
183  return;
184  }
185 
186  const ClassProperty* pClassProperty = getClassProperty(propertyId);
187  if (!pClassProperty) {
188  callback(
189  propertyId,
192  return;
193  }
194 
195  if (pClassProperty->array) {
196  callback(
197  propertyId,
200  return;
201  }
202 
203  PropertyType type = convertStringToPropertyType(pClassProperty->type);
204  PropertyComponentType componentType = PropertyComponentType::None;
205  if (pClassProperty->componentType) {
206  componentType =
207  convertStringToPropertyComponentType(*pClassProperty->componentType);
208  }
209 
210  bool normalized = pClassProperty->normalized;
211  if (normalized && !isPropertyComponentTypeInteger(componentType)) {
212  callback(
213  propertyId,
216  return;
217  }
218 
219  if (type == PropertyType::Scalar) {
220  if (normalized) {
221  getScalarPropertyViewImpl<Callback, true>(
222  primitive,
223  propertyId,
224  *pClassProperty,
225  componentType,
226  std::forward<Callback>(callback));
227  } else {
228  getScalarPropertyViewImpl<Callback, false>(
229  primitive,
230  propertyId,
231  *pClassProperty,
232  componentType,
233  std::forward<Callback>(callback));
234  }
235  return;
236  }
237 
238  if (isPropertyTypeVecN(type)) {
239  if (normalized) {
240  getVecNPropertyViewImpl<Callback, true>(
241  primitive,
242  propertyId,
243  *pClassProperty,
244  type,
245  componentType,
246  std::forward<Callback>(callback));
247  } else {
248  getVecNPropertyViewImpl<Callback, false>(
249  primitive,
250  propertyId,
251  *pClassProperty,
252  type,
253  componentType,
254  std::forward<Callback>(callback));
255  }
256  return;
257  }
258 
259  if (isPropertyTypeMatN(type)) {
260  if (normalized) {
261  getMatNPropertyViewImpl<Callback, true>(
262  primitive,
263  propertyId,
264  *pClassProperty,
265  type,
266  componentType,
267  std::forward<Callback>(callback));
268  } else {
269  getMatNPropertyViewImpl<Callback, false>(
270  primitive,
271  propertyId,
272  *pClassProperty,
273  type,
274  componentType,
275  std::forward<Callback>(callback));
276  }
277  return;
278  }
279 
280  callback(
281  propertyId,
284  return;
285  }
286 
306  template <typename Callback>
307  void
308  forEachProperty(const MeshPrimitive& primitive, Callback&& callback) const {
309  for (const auto& property : this->_pClass->properties) {
311  primitive,
312  property.first,
313  std::forward<Callback>(callback));
314  }
315  }
316 
317 private:
318  template <typename T, bool Normalized>
319  PropertyAttributePropertyView<T, Normalized> getEmptyPropertyViewWithDefault(
320  const MeshPrimitive& primitive,
321  const ClassProperty& classProperty) const {
322  // To make the view have a nonzero size, find the POSITION attribute and get
323  // its accessor count. If it doesn't exist or is somehow erroneous, just
324  // mark the property as nonexistent.
325  if (primitive.attributes.find("POSITION") == primitive.attributes.end()) {
328  }
329 
330  const Accessor* pAccessor = _pModel->getSafe<Accessor>(
331  &_pModel->accessors,
332  primitive.attributes.at("POSITION"));
333  if (!pAccessor) {
334  return PropertyAttributePropertyView<T, Normalized>(
336  }
337 
338  return PropertyAttributePropertyView<T, Normalized>(
339  classProperty,
340  pAccessor->count);
341  }
342 
343  template <typename T, bool Normalized>
344  PropertyAttributePropertyView<T, Normalized> getPropertyViewImpl(
345  const MeshPrimitive& primitive,
346  const std::string& propertyId,
347  const ClassProperty& classProperty) const {
348  auto propertyAttributePropertyIter =
349  _pPropertyAttribute->properties.find(propertyId);
350  if (propertyAttributePropertyIter ==
351  _pPropertyAttribute->properties.end()) {
352  if (!classProperty.required && classProperty.defaultProperty) {
353  // If the property was omitted from the property attribute, it is still
354  // technically valid if it specifies a default value. Try to create a
355  // view that just returns the default value.
356  return getEmptyPropertyViewWithDefault<T, Normalized>(
357  primitive,
358  classProperty);
359  }
360 
361  // Otherwise, the property is erroneously nonexistent.
362  return PropertyAttributePropertyView<T, Normalized>(
364  }
365 
366  const PropertyAttributeProperty& propertyAttributeProperty =
367  propertyAttributePropertyIter->second;
368 
369  return createPropertyView<T, Normalized>(
370  primitive,
371  classProperty,
372  propertyAttributeProperty);
373  }
374 
375  template <typename Callback, bool Normalized>
376  void getScalarPropertyViewImpl(
377  const MeshPrimitive& primitive,
378  const std::string& propertyId,
379  const ClassProperty& classProperty,
380  PropertyComponentType componentType,
381  Callback&& callback) const {
382  switch (componentType) {
383  case PropertyComponentType::Int8:
384  callback(
385  propertyId,
386  getPropertyViewImpl<int8_t, Normalized>(
387  primitive,
388  propertyId,
389  classProperty));
390  return;
391  case PropertyComponentType::Uint8:
392  callback(
393  propertyId,
394  getPropertyViewImpl<uint8_t, Normalized>(
395  primitive,
396  propertyId,
397  classProperty));
398  return;
399  case PropertyComponentType::Int16:
400  callback(
401  propertyId,
402  getPropertyViewImpl<int16_t, Normalized>(
403  primitive,
404  propertyId,
405  classProperty));
406  return;
407  case PropertyComponentType::Uint16:
408  callback(
409  propertyId,
410  getPropertyViewImpl<uint16_t, Normalized>(
411  primitive,
412  propertyId,
413  classProperty));
414  break;
415  case PropertyComponentType::Float32:
416  callback(
417  propertyId,
418  getPropertyViewImpl<float, false>(
419  primitive,
420  propertyId,
421  classProperty));
422  break;
423  default:
424  callback(
425  propertyId,
426  PropertyAttributePropertyView<uint8_t>(
428  break;
429  }
430  }
431 
432  template <typename Callback, glm::length_t N, bool Normalized>
433  void getVecNPropertyViewImpl(
434  const MeshPrimitive& primitive,
435  const std::string& propertyId,
436  const ClassProperty& classProperty,
437  PropertyComponentType componentType,
438  Callback&& callback) const {
439  switch (componentType) {
440  case PropertyComponentType::Int8:
441  callback(
442  propertyId,
443  getPropertyViewImpl<glm::vec<N, int8_t>, Normalized>(
444  primitive,
445  propertyId,
446  classProperty));
447  break;
448  case PropertyComponentType::Uint8:
449  callback(
450  propertyId,
451  getPropertyViewImpl<glm::vec<N, uint8_t>, Normalized>(
452  primitive,
453  propertyId,
454  classProperty));
455  break;
456  case PropertyComponentType::Int16:
457  callback(
458  propertyId,
459  getPropertyViewImpl<glm::vec<N, int16_t>, Normalized>(
460  primitive,
461  propertyId,
462  classProperty));
463  break;
464  case PropertyComponentType::Uint16:
465  callback(
466  propertyId,
467  getPropertyViewImpl<glm::vec<N, uint16_t>, Normalized>(
468  primitive,
469  propertyId,
470  classProperty));
471  break;
472  case PropertyComponentType::Float32:
473  callback(
474  propertyId,
475  getPropertyViewImpl<glm::vec<N, float>, false>(
476  primitive,
477  propertyId,
478  classProperty));
479  break;
480  default:
481  callback(
482  propertyId,
483  PropertyAttributePropertyView<uint8_t>(
485  break;
486  }
487  }
488 
489  template <typename Callback, bool Normalized>
490  void getVecNPropertyViewImpl(
491  const MeshPrimitive& primitive,
492  const std::string& propertyId,
493  const ClassProperty& classProperty,
494  PropertyType type,
495  PropertyComponentType componentType,
496  Callback&& callback) const {
497  const glm::length_t N = getDimensionsFromPropertyType(type);
498  switch (N) {
499  case 2:
500  getVecNPropertyViewImpl<Callback, 2, Normalized>(
501  primitive,
502  propertyId,
503  classProperty,
504  componentType,
505  std::forward<Callback>(callback));
506  break;
507  case 3:
508  getVecNPropertyViewImpl<Callback, 3, Normalized>(
509  primitive,
510  propertyId,
511  classProperty,
512  componentType,
513  std::forward<Callback>(callback));
514  break;
515  case 4:
516  getVecNPropertyViewImpl<Callback, 4, Normalized>(
517  primitive,
518  propertyId,
519  classProperty,
520  componentType,
521  std::forward<Callback>(callback));
522  break;
523  default:
524  callback(
525  propertyId,
526  PropertyAttributePropertyView<uint8_t>(
528  break;
529  }
530  }
531 
532  template <typename Callback, glm::length_t N, bool Normalized>
533  void getMatNPropertyViewImpl(
534  const MeshPrimitive& primitive,
535  const std::string& propertyId,
536  const ClassProperty& classProperty,
537  PropertyComponentType componentType,
538  Callback&& callback) const {
539  switch (componentType) {
540  case PropertyComponentType::Int8:
541  callback(
542  propertyId,
543  getPropertyViewImpl<glm::mat<N, N, int8_t>, Normalized>(
544  primitive,
545  propertyId,
546  classProperty));
547  break;
548  case PropertyComponentType::Uint8:
549  callback(
550  propertyId,
551  getPropertyViewImpl<glm::mat<N, N, uint8_t>, Normalized>(
552  primitive,
553  propertyId,
554  classProperty));
555  break;
556  case PropertyComponentType::Int16:
557  callback(
558  propertyId,
559  getPropertyViewImpl<glm::mat<N, N, int16_t>, Normalized>(
560  primitive,
561  propertyId,
562  classProperty));
563  break;
564  case PropertyComponentType::Uint16:
565  callback(
566  propertyId,
567  getPropertyViewImpl<glm::mat<N, N, uint16_t>, Normalized>(
568  primitive,
569  propertyId,
570  classProperty));
571  break;
572  case PropertyComponentType::Float32:
573  callback(
574  propertyId,
575  getPropertyViewImpl<glm::mat<N, N, float>, false>(
576  primitive,
577  propertyId,
578  classProperty));
579  break;
580  default:
581  callback(
582  propertyId,
583  PropertyAttributePropertyView<uint8_t>(
585  break;
586  }
587  }
588 
589  template <typename Callback, bool Normalized>
590  void getMatNPropertyViewImpl(
591  const MeshPrimitive& primitive,
592  const std::string& propertyId,
593  const ClassProperty& classProperty,
594  PropertyType type,
595  PropertyComponentType componentType,
596  Callback&& callback) const {
597  glm::length_t N = getDimensionsFromPropertyType(type);
598  switch (N) {
599  case 2:
600  getMatNPropertyViewImpl<Callback, 2, Normalized>(
601  primitive,
602  propertyId,
603  classProperty,
604  componentType,
605  std::forward<Callback>(callback));
606  break;
607  case 3:
608  getMatNPropertyViewImpl<Callback, 3, Normalized>(
609  primitive,
610  propertyId,
611  classProperty,
612  componentType,
613  std::forward<Callback>(callback));
614  break;
615  case 4:
616  getMatNPropertyViewImpl<Callback, 4, Normalized>(
617  primitive,
618  propertyId,
619  classProperty,
620  componentType,
621  std::forward<Callback>(callback));
622  break;
623  default:
624  callback(
625  propertyId,
626  PropertyAttributePropertyView<uint8_t>(
628  break;
629  }
630  }
631 
632  template <typename T, bool Normalized>
633  PropertyAttributePropertyView<T, Normalized> createPropertyView(
634  const MeshPrimitive& primitive,
635  const ClassProperty& classProperty,
636  const PropertyAttributeProperty& propertyAttributeProperty) const {
637  const PropertyType type = convertStringToPropertyType(classProperty.type);
638  if (TypeToPropertyType<T>::value != type) {
639  return PropertyAttributePropertyView<T, Normalized>(
641  }
642 
643  const PropertyComponentType componentType =
644  convertStringToPropertyComponentType(
645  classProperty.componentType.value_or(""));
646  if (TypeToPropertyType<T>::component != componentType) {
647  return PropertyAttributePropertyView<T, Normalized>(
649  }
650 
651  if (classProperty.normalized != Normalized) {
652  return PropertyAttributePropertyView<T, Normalized>(
654  }
655 
656  if (primitive.attributes.find(propertyAttributeProperty.attribute) ==
657  primitive.attributes.end()) {
658  return PropertyAttributePropertyView<T, Normalized>(
660  }
661 
662  const Accessor* pAccessor = _pModel->getSafe<Accessor>(
663  &_pModel->accessors,
664  primitive.attributes.at(propertyAttributeProperty.attribute));
665  if (!pAccessor) {
666  return PropertyAttributePropertyView<T, Normalized>(
668  }
669 
670  if (getAccessorTypeAsPropertyType(*pAccessor) != type) {
671  return PropertyAttributePropertyView<T, Normalized>(
673  }
674 
675  if (getAccessorComponentTypeAsPropertyComponentType(*pAccessor) !=
676  componentType) {
677  return PropertyAttributePropertyView<T, Normalized>(
678  PropertyAttributePropertyViewStatus::
679  ErrorAccessorComponentTypeMismatch);
680  }
681 
682  if (pAccessor->normalized != Normalized) {
683  return PropertyAttributePropertyView<T, Normalized>(
684  PropertyAttributePropertyViewStatus::
685  ErrorAccessorNormalizationMismatch);
686  }
687 
688  AccessorView<T> accessorView = AccessorView<T>(*_pModel, *pAccessor);
689  if (accessorView.status() != AccessorViewStatus::Valid) {
690  switch (accessorView.status()) {
692  return PropertyAttributePropertyView<T, Normalized>(
695  return PropertyAttributePropertyView<T, Normalized>(
698  return PropertyAttributePropertyView<T, Normalized>(
701  return PropertyAttributePropertyView<T, Normalized>(
703  default:
704  return PropertyAttributePropertyView<T, Normalized>(
706  }
707  }
708 
709  return PropertyAttributePropertyView<T, Normalized>(
710  propertyAttributeProperty,
711  classProperty,
712  accessorView);
713  }
714 
715  const Model* _pModel;
716  const PropertyAttribute* _pPropertyAttribute;
717  const Class* _pClass;
718 
720 };
721 
722 } // 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.
A view on a PropertyAttribute.
const ClassProperty * getClassProperty(const std::string &propertyId) const
Finds the ClassProperty that describes the type information of the property with the specified id.
PropertyAttributeView(const Model &model, const PropertyAttribute &propertyAttribute) noexcept
Construct a PropertyAttributeView.
PropertyAttributeViewStatus status() const noexcept
Gets the status of this property attribute view.
const Class * getClass() const noexcept
Gets the Class that this property attribute conforms to.
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.
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...
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...
static const PropertyViewStatusType ErrorTypeMismatch
This property view's type does not match what is specified in ClassProperty::type.
Definition: PropertyView.h:53
static const PropertyViewStatusType ErrorNonexistentProperty
This property view is trying to view a property that does not exist.
Definition: PropertyView.h:47
static const PropertyViewStatusType ErrorInvalidNormalization
This property says it is normalized, but it does not have an integer component type.
Definition: PropertyView.h:71
static const PropertyViewStatusType ErrorNormalizationMismatch
This property view's normalization differs from what is specified in ClassProperty::normalized.
Definition: PropertyView.h:77
static const PropertyViewStatusType ErrorComponentTypeMismatch
This property view's component type does not match what is specified in ClassProperty::componentType.
Definition: PropertyView.h:59
Classes for working with glTF models.
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.
@ 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.
A class property.
Definition: ClassProperty.h:19
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.
Definition: ClassProperty.h:98
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.
Definition: ClassProperty.h:89
A class containing a set of properties.
Definition: Class.h:18
std::unordered_map< std::string, CesiumGltf::ClassProperty > properties
A dictionary, where each key is a property ID and each value is an object defining the property....
Definition: Class.h:36
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.
Definition: MeshPrimitive.h:18
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...
Definition: MeshPrimitive.h:45
std::vector< CesiumGltf::Accessor > accessors
An array of accessors.
Definition: ModelSpec.h:49
The root object for a glTF asset.
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:179
Properties conforming to a class, organized as property values stored in attributes.
std::optional< std::string > name
The name of the property attribute, e.g. for display purposes.
std::unordered_map< std::string, CesiumGltf::PropertyAttributeProperty > properties
A dictionary, where each key corresponds to a property ID in the class' properties dictionary and eac...