cesium-native  0.41.0
PropertyTextureView.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/PropertyTexture.h"
8 #include "CesiumGltf/PropertyTexturePropertyView.h"
9 #include "CesiumGltf/TextureView.h"
10 
11 namespace CesiumGltf {
23  Valid,
24 
29 
34 
40 };
41 
51 public:
60  const Model& model,
61  const PropertyTexture& propertyTexture) noexcept;
62 
69  PropertyTextureViewStatus status() const noexcept { return this->_status; }
70 
75  const std::optional<std::string>& name() const noexcept {
76  return _pPropertyTexture->name;
77  }
78 
85  const Class* getClass() const noexcept { return _pClass; }
86 
95  const ClassProperty* getClassProperty(const std::string& propertyId) const;
96 
121  template <typename T, bool Normalized = false>
123  const std::string& propertyId,
124  const TextureViewOptions& propertyOptions = TextureViewOptions()) const {
125  if (this->_status != PropertyTextureViewStatus::Valid) {
128  }
129 
130  const ClassProperty* pClassProperty = getClassProperty(propertyId);
131  if (!pClassProperty) {
134  }
135 
136  return getPropertyViewImpl<T, Normalized>(
137  propertyId,
138  *pClassProperty,
139  propertyOptions);
140  }
141 
162  template <typename Callback>
164  const std::string& propertyId,
165  Callback&& callback,
166  const TextureViewOptions& propertyOptions = TextureViewOptions()) const {
167  if (this->_status != PropertyTextureViewStatus::Valid) {
168  callback(
169  propertyId,
172  return;
173  }
174 
175  const ClassProperty* pClassProperty = getClassProperty(propertyId);
176  if (!pClassProperty) {
177  callback(
178  propertyId,
181  return;
182  }
183 
184  PropertyType type = convertStringToPropertyType(pClassProperty->type);
185  PropertyComponentType componentType = PropertyComponentType::None;
186  if (pClassProperty->componentType) {
187  componentType =
188  convertStringToPropertyComponentType(*pClassProperty->componentType);
189  }
190 
191  bool normalized = pClassProperty->normalized;
192  if (normalized && !isPropertyComponentTypeInteger(componentType)) {
193  // Only integer components may be normalized.
194  callback(
195  propertyId,
198  return;
199  }
200 
201  if (pClassProperty->array) {
202  if (normalized) {
203  getArrayPropertyViewImpl<Callback, true>(
204  propertyId,
205  *pClassProperty,
206  type,
207  componentType,
208  std::forward<Callback>(callback),
209  propertyOptions);
210  } else {
211  getArrayPropertyViewImpl<Callback, false>(
212  propertyId,
213  *pClassProperty,
214  type,
215  componentType,
216  std::forward<Callback>(callback),
217  propertyOptions);
218  }
219  return;
220  }
221 
222  if (type == PropertyType::Scalar) {
223  if (normalized) {
224  getScalarPropertyViewImpl<Callback, true>(
225  propertyId,
226  *pClassProperty,
227  componentType,
228  std::forward<Callback>(callback),
229  propertyOptions);
230  } else {
231  getScalarPropertyViewImpl<Callback, false>(
232  propertyId,
233  *pClassProperty,
234  componentType,
235  std::forward<Callback>(callback),
236  propertyOptions);
237  }
238  return;
239  }
240 
241  if (isPropertyTypeVecN(type)) {
242  if (normalized) {
243  getVecNPropertyViewImpl<Callback, true>(
244  propertyId,
245  *pClassProperty,
246  type,
247  componentType,
248  std::forward<Callback>(callback),
249  propertyOptions);
250  } else {
251  getVecNPropertyViewImpl<Callback, false>(
252  propertyId,
253  *pClassProperty,
254  type,
255  componentType,
256  std::forward<Callback>(callback),
257  propertyOptions);
258  }
259  return;
260  }
261 
262  callback(
263  propertyId,
266  return;
267  }
268 
290  template <typename Callback>
292  Callback&& callback,
293  const TextureViewOptions& propertyOptions = TextureViewOptions()) const {
294  for (const auto& property : this->_pClass->properties) {
296  property.first,
297  std::forward<Callback>(callback),
298  propertyOptions);
299  }
300  }
301 
302 private:
303  template <typename T, bool Normalized>
304  PropertyTexturePropertyView<T, Normalized> getPropertyViewImpl(
305  const std::string& propertyId,
306  const ClassProperty& classProperty,
307  const TextureViewOptions& propertyOptions) const {
308  auto propertyTexturePropertyIter =
309  _pPropertyTexture->properties.find(propertyId);
310  if (propertyTexturePropertyIter == _pPropertyTexture->properties.end()) {
311  if (!classProperty.required && classProperty.defaultProperty) {
312  // If the property was omitted from the property texture, it is still
313  // technically valid if it specifies a default value. Create a view that
314  // just returns the default value.
315  return PropertyTexturePropertyView<T, Normalized>(classProperty);
316  }
317 
318  return PropertyTexturePropertyView<T, Normalized>(
320  }
321 
322  const PropertyTextureProperty& propertyTextureProperty =
323  propertyTexturePropertyIter->second;
324 
325  if constexpr (IsMetadataScalar<T>::value) {
326  return createScalarPropertyView<T, Normalized>(
327  classProperty,
328  propertyTextureProperty,
329  propertyOptions);
330  }
331 
332  if constexpr (IsMetadataVecN<T>::value) {
333  return createVecNPropertyView<T, Normalized>(
334  classProperty,
335  propertyTextureProperty,
336  propertyOptions);
337  }
338 
339  if constexpr (IsMetadataArray<T>::value) {
340  return createArrayPropertyView<
341  typename MetadataArrayType<T>::type,
342  Normalized>(classProperty, propertyTextureProperty, propertyOptions);
343  }
344  }
345 
346  template <typename Callback, bool Normalized>
347  void getArrayPropertyViewImpl(
348  const std::string& propertyId,
349  const ClassProperty& classProperty,
350  PropertyType type,
351  PropertyComponentType componentType,
352  Callback&& callback,
353  const TextureViewOptions& propertyOptions) const {
354  // Only scalar arrays are supported.
355  if (type != PropertyType::Scalar) {
356  callback(
357  propertyId,
358  PropertyTexturePropertyView<uint8_t>(
360  return;
361  }
362 
363  int64_t count = classProperty.count.value_or(0);
364  if (count <= 0 || count > 4) {
365  callback(
366  propertyId,
367  PropertyTexturePropertyView<uint8_t>(
369  return;
370  }
371 
372  switch (componentType) {
373  case PropertyComponentType::Int8:
374  callback(
375  propertyId,
376  getPropertyViewImpl<PropertyArrayView<int8_t>, Normalized>(
377  propertyId,
378  classProperty,
379  propertyOptions));
380  break;
381  case PropertyComponentType::Uint8:
382  callback(
383  propertyId,
384  getPropertyViewImpl<PropertyArrayView<uint8_t>, Normalized>(
385  propertyId,
386  classProperty,
387  propertyOptions));
388  break;
389  case PropertyComponentType::Int16:
390  callback(
391  propertyId,
392  getPropertyViewImpl<PropertyArrayView<int16_t>, Normalized>(
393  propertyId,
394  classProperty,
395  propertyOptions));
396  break;
397  case PropertyComponentType::Uint16:
398  callback(
399  propertyId,
400  getPropertyViewImpl<PropertyArrayView<uint16_t>, Normalized>(
401  propertyId,
402  classProperty,
403  propertyOptions));
404  break;
405  default:
406  callback(
407  propertyId,
408  PropertyTexturePropertyView<uint8_t>(
410  break;
411  }
412  }
413 
414  template <typename Callback, bool Normalized>
415  void getScalarPropertyViewImpl(
416  const std::string& propertyId,
417  const ClassProperty& classProperty,
418  PropertyComponentType componentType,
419  Callback&& callback,
420  const TextureViewOptions& propertyOptions) const {
421  switch (componentType) {
422  case PropertyComponentType::Int8:
423  callback(
424  propertyId,
425  getPropertyViewImpl<int8_t, Normalized>(
426  propertyId,
427  classProperty,
428  propertyOptions));
429  return;
430  case PropertyComponentType::Uint8:
431  callback(
432  propertyId,
433  getPropertyViewImpl<uint8_t, Normalized>(
434  propertyId,
435  classProperty,
436  propertyOptions));
437  return;
438  case PropertyComponentType::Int16:
439  callback(
440  propertyId,
441  getPropertyViewImpl<int16_t, Normalized>(
442  propertyId,
443  classProperty,
444  propertyOptions));
445  return;
446  case PropertyComponentType::Uint16:
447  callback(
448  propertyId,
449  getPropertyViewImpl<uint16_t, Normalized>(
450  propertyId,
451  classProperty,
452  propertyOptions));
453  break;
454  case PropertyComponentType::Int32:
455  callback(
456  propertyId,
457  getPropertyViewImpl<int32_t, Normalized>(
458  propertyId,
459  classProperty,
460  propertyOptions));
461  break;
462  case PropertyComponentType::Uint32:
463  callback(
464  propertyId,
465  getPropertyViewImpl<uint32_t, Normalized>(
466  propertyId,
467  classProperty,
468  propertyOptions));
469  break;
470  case PropertyComponentType::Float32:
471  callback(
472  propertyId,
473  getPropertyViewImpl<float, false>(
474  propertyId,
475  classProperty,
476  propertyOptions));
477  break;
478  default:
479  callback(
480  propertyId,
481  PropertyTexturePropertyView<uint8_t>(
483  break;
484  }
485  }
486 
487  template <typename Callback, glm::length_t N, bool Normalized>
488  void getVecNPropertyViewImpl(
489  const std::string& propertyId,
490  const ClassProperty& classProperty,
491  PropertyComponentType componentType,
492  Callback&& callback,
493  const TextureViewOptions& propertyOptions) const {
494  switch (componentType) {
495  case PropertyComponentType::Int8:
496  callback(
497  propertyId,
498  getPropertyViewImpl<glm::vec<N, int8_t>, Normalized>(
499  propertyId,
500  classProperty,
501  propertyOptions));
502  break;
503  case PropertyComponentType::Uint8:
504  callback(
505  propertyId,
506  getPropertyViewImpl<glm::vec<N, uint8_t>, Normalized>(
507  propertyId,
508  classProperty,
509  propertyOptions));
510  break;
511  case PropertyComponentType::Int16:
512  if constexpr (N == 2) {
513  callback(
514  propertyId,
515  getPropertyViewImpl<glm::vec<N, int16_t>, Normalized>(
516  propertyId,
517  classProperty,
518  propertyOptions));
519  break;
520  }
521  [[fallthrough]];
522  case PropertyComponentType::Uint16:
523  if constexpr (N == 2) {
524  callback(
525  propertyId,
526  getPropertyViewImpl<glm::vec<N, uint16_t>, Normalized>(
527  propertyId,
528  classProperty,
529  propertyOptions));
530  break;
531  }
532  [[fallthrough]];
533  default:
534  callback(
535  propertyId,
536  PropertyTexturePropertyView<uint8_t>(
538  break;
539  }
540  }
541 
542  template <typename Callback, bool Normalized>
543  void getVecNPropertyViewImpl(
544  const std::string& propertyId,
545  const ClassProperty& classProperty,
546  PropertyType type,
547  PropertyComponentType componentType,
548  Callback&& callback,
549  const TextureViewOptions& propertyOptions) const {
550  const glm::length_t N = getDimensionsFromPropertyType(type);
551  switch (N) {
552  case 2:
553  getVecNPropertyViewImpl<Callback, 2, Normalized>(
554  propertyId,
555  classProperty,
556  componentType,
557  std::forward<Callback>(callback),
558  propertyOptions);
559  break;
560  case 3:
561  getVecNPropertyViewImpl<Callback, 3, Normalized>(
562  propertyId,
563  classProperty,
564  componentType,
565  std::forward<Callback>(callback),
566  propertyOptions);
567  break;
568  case 4:
569  getVecNPropertyViewImpl<Callback, 4, Normalized>(
570  propertyId,
571  classProperty,
572  componentType,
573  std::forward<Callback>(callback),
574  propertyOptions);
575  break;
576  default:
577  callback(
578  propertyId,
579  PropertyTexturePropertyView<uint8_t>(
581  break;
582  }
583  }
584 
585  template <typename T, bool Normalized>
586  PropertyTexturePropertyView<T, Normalized> createScalarPropertyView(
587  const ClassProperty& classProperty,
588  [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty,
589  const TextureViewOptions& propertyOptions) const {
590  if (classProperty.array) {
591  return PropertyTexturePropertyView<T, Normalized>(
593  }
594 
595  const PropertyType type = convertStringToPropertyType(classProperty.type);
596  if (TypeToPropertyType<T>::value != type) {
597  return PropertyTexturePropertyView<T, Normalized>(
599  }
600 
601  const PropertyComponentType componentType =
602  convertStringToPropertyComponentType(
603  classProperty.componentType.value_or(""));
604  if (TypeToPropertyType<T>::component != componentType) {
605  return PropertyTexturePropertyView<T, Normalized>(
607  }
608 
609  if (classProperty.normalized != Normalized) {
610  return PropertyTexturePropertyView<T, Normalized>(
612  }
613 
614  // Only up to four bytes of image data are supported.
615  if constexpr (sizeof(T) <= 4) {
616  return createPropertyViewImpl<T, Normalized>(
617  classProperty,
618  propertyTextureProperty,
619  sizeof(T),
620  propertyOptions);
621  } else {
622  return PropertyTexturePropertyView<T, Normalized>(
624  }
625  }
626 
627  template <typename T, bool Normalized>
628  PropertyTexturePropertyView<T, Normalized> createVecNPropertyView(
629  const ClassProperty& classProperty,
630  [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty,
631  [[maybe_unused]] const TextureViewOptions& propertyOptions) const {
632  if (classProperty.array) {
633  return PropertyTexturePropertyView<T, Normalized>(
635  }
636 
637  const PropertyType type = convertStringToPropertyType(classProperty.type);
638  if (TypeToPropertyType<T>::value != type) {
639  return PropertyTexturePropertyView<T, Normalized>(
641  }
642 
643  const PropertyComponentType componentType =
644  convertStringToPropertyComponentType(
645  classProperty.componentType.value_or(""));
646  if (TypeToPropertyType<T>::component != componentType) {
647  return PropertyTexturePropertyView<T, Normalized>(
649  }
650 
651  if (classProperty.normalized != Normalized) {
652  return PropertyTexturePropertyView<T, Normalized>(
654  }
655 
656  // Only up to four bytes of image data are supported.
657  if constexpr (sizeof(T) <= 4) {
658  return createPropertyViewImpl<T, Normalized>(
659  classProperty,
660  propertyTextureProperty,
661  sizeof(T),
662  propertyOptions);
663  } else {
664  return PropertyTexturePropertyView<T, Normalized>(
666  }
667  }
668 
669  template <typename T, bool Normalized>
670  PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>
671  createArrayPropertyView(
672  const ClassProperty& classProperty,
673  [[maybe_unused]] const PropertyTextureProperty& propertyTextureProperty,
674  [[maybe_unused]] const TextureViewOptions& propertyOptions) const {
675  if (!classProperty.array) {
676  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
678  }
679 
680  const PropertyType type = convertStringToPropertyType(classProperty.type);
681  if (TypeToPropertyType<T>::value != type) {
682  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
684  }
685 
686  const PropertyComponentType componentType =
687  convertStringToPropertyComponentType(
688  classProperty.componentType.value_or(""));
689  if (TypeToPropertyType<T>::component != componentType) {
690  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
692  }
693 
694  if (classProperty.normalized != Normalized) {
695  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
697  }
698 
699  // Only scalar arrays are supported. The scalar component type must not
700  // exceed two bytes.
701  if constexpr (IsMetadataScalar<T>::value && sizeof(T) <= 4) {
702  // Only up to four elements are supported.
703  int64_t count = classProperty.count.value_or(0);
704  if (count <= 0 || count > 4) {
705  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
707  }
708 
709  if (count * sizeof(T) > 4) {
710  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
712  }
713 
714  return createPropertyViewImpl<PropertyArrayView<T>, Normalized>(
715  classProperty,
716  propertyTextureProperty,
717  count * sizeof(T),
718  propertyOptions);
719  } else {
720  return PropertyTexturePropertyView<PropertyArrayView<T>, Normalized>(
722  }
723  }
724 
725  template <typename T, bool Normalized>
726  PropertyTexturePropertyView<T, Normalized> createPropertyViewImpl(
727  const ClassProperty& classProperty,
728  const PropertyTextureProperty& propertyTextureProperty,
729  size_t elementSize,
730  const TextureViewOptions& propertyOptions) const {
731  int32_t samplerIndex;
732  int32_t imageIndex;
733 
734  auto status =
735  getTextureSafe(propertyTextureProperty.index, samplerIndex, imageIndex);
736 
738  return PropertyTexturePropertyView<T, Normalized>(status);
739  }
740 
741  status = checkSampler(samplerIndex);
743  return PropertyTexturePropertyView<T, Normalized>(status);
744  }
745 
746  status = checkImage(imageIndex);
748  return PropertyTexturePropertyView<T, Normalized>(status);
749  }
750 
752  _pModel->images[imageIndex].pAsset;
753  const std::vector<int64_t>& channels = propertyTextureProperty.channels;
754 
755  status = checkChannels(channels, *pImage);
757  return PropertyTexturePropertyView<T, Normalized>(status);
758  }
759 
760  if (channels.size() * pImage->bytesPerChannel != elementSize) {
762  }
763 
764  return PropertyTexturePropertyView<T, Normalized>(
765  propertyTextureProperty,
766  classProperty,
767  _pModel->samplers[samplerIndex],
768  *pImage,
769  propertyOptions);
770  }
771 
772  PropertyViewStatusType getTextureSafe(
773  const int32_t textureIndex,
774  int32_t& samplerIndex,
775  int32_t& imageIndex) const noexcept;
776 
777  PropertyViewStatusType
778  checkSampler(const int32_t samplerIndex) const noexcept;
779 
780  PropertyViewStatusType checkImage(const int32_t imageIndex) const noexcept;
781 
782  PropertyViewStatusType checkChannels(
783  const std::vector<int64_t>& channels,
784  const ImageAsset& image) const noexcept;
785 
786  const Model* _pModel;
787  const PropertyTexture* _pPropertyTexture;
788  const Class* _pClass;
789 
791 };
792 } // namespace CesiumGltf
static const int ErrorUnsupportedProperty
This property view is associated with a ClassProperty of an unsupported type.
static const int ErrorChannelsAndTypeMismatch
The channels of this property texture property do not provide the exact number of bytes required by t...
static const int ErrorInvalidPropertyTexture
This property view was initialized from an invalid PropertyTexture.
A view of the data specified by a PropertyTextureProperty.
A view on a PropertyTexture.
PropertyTextureView(const Model &model, const PropertyTexture &propertyTexture) noexcept
Construct a PropertyTextureView.
PropertyTextureViewStatus status() const noexcept
Gets the status of this property texture view.
void forEachProperty(Callback &&callback, const TextureViewOptions &propertyOptions=TextureViewOptions()) const
Iterates over each property in the PropertyTexture with a callback that accepts a property id and a P...
void getPropertyView(const std::string &propertyId, Callback &&callback, const TextureViewOptions &propertyOptions=TextureViewOptions()) const
Gets a PropertyTexturePropertyView through a callback that accepts a property id and a PropertyTextur...
PropertyTexturePropertyView< T, Normalized > getPropertyView(const std::string &propertyId, const TextureViewOptions &propertyOptions=TextureViewOptions()) const
Gets a PropertyTexturePropertyView that views the data of a property stored in the PropertyTexture.
const ClassProperty * getClassProperty(const std::string &propertyId) const
Finds the ClassProperty that describes the type information of the property with the specified id.
const Class * getClass() const noexcept
Gets the Class that this property texture conforms to.
const std::optional< std::string > & name() const noexcept
Gets the name of the property texture being viewed. Returns std::nullopt if no name was specified.
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 Valid
This property view is valid and ready to use.
Definition: PropertyView.h:32
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 ErrorArrayTypeMismatch
This property view differs from what is specified in ClassProperty::array.
Definition: PropertyView.h:65
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
A smart pointer that calls addReference and releaseReference on the controlled object.
Classes for working with glTF models.
PropertyTextureViewStatus
Indicates the status of a property texture view.
@ Valid
This property texture view is valid and ready to use.
@ ErrorClassNotFound
The property texture'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.
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
bool required
If required, the property must be present in every entity conforming to the class....
std::optional< CesiumUtility::JsonValue > defaultProperty
A default value to use when encountering a noData value or an omitted property. The value is given in...
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
std::vector< CesiumGltf::Sampler > samplers
An array of samplers.
Definition: ModelSpec.h:114
std::vector< CesiumGltf::Image > images
An array of images.
Definition: ModelSpec.h:88
The root object for a glTF asset.
Definition: Model.h:14
Properties conforming to a class, organized as property values stored in textures.
std::optional< std::string > name
The name of the property texture, e.g. for display purposes.
std::unordered_map< std::string, CesiumGltf::PropertyTextureProperty > properties
A dictionary, where each key corresponds to a property ID in the class' properties dictionary and eac...
Describes options for constructing a view on a glTF texture.
Definition: TextureView.h:18