cesium-native 0.64.0
Loading...
Searching...
No Matches
PropertyTexturePropertyView.h
1#pragma once
2
3#include <CesiumGltf/KhrTextureTransform.h>
4#include <CesiumGltf/PropertyTextureProperty.h>
5#include <CesiumGltf/PropertyTransformations.h>
6#include <CesiumGltf/PropertyTypeTraits.h>
7#include <CesiumGltf/PropertyView.h>
8#include <CesiumGltf/Sampler.h>
9#include <CesiumGltf/TextureView.h>
10#include <CesiumImage/ImageAsset.h>
11#include <CesiumUtility/Assert.h>
12
13#include <array>
14#include <cmath>
15#include <cstdint>
16#include <optional>
17
18namespace CesiumGltf {
28public:
33 static const int ErrorInvalidPropertyTexture = 15;
34
39 static const int ErrorUnsupportedProperty = 16;
40
44 static const int ErrorInvalidTexture = 17;
45
49 static const int ErrorInvalidSampler = 18;
50
54 static const int ErrorInvalidImage = 19;
55
59 static const int ErrorEmptyImage = 20;
60
65 static const int ErrorInvalidBytesPerChannel = 21;
66
74 static const int ErrorInvalidChannels = 22;
75
82 static const int ErrorChannelsAndTypeMismatch = 23;
83};
84
92template <typename ElementType>
93ElementType assembleScalarValue(const std::span<uint8_t> bytes) noexcept {
94 if constexpr (std::is_same_v<ElementType, float>) {
95 CESIUM_ASSERT(
96 bytes.size() == sizeof(float) &&
97 "Not enough channel inputs to construct a float.");
98 uint32_t resultAsUint = 0;
99 for (size_t i = 0; i < bytes.size(); i++) {
100 resultAsUint |= static_cast<uint32_t>(bytes[i]) << i * 8;
101 }
102
103 // Reinterpret the bits as a float.
104 // We need to memcpy to avoid a "dereferencing type-punned pointer will
105 // break strict-aliasing rules" error on GCC. See:
106 // https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8#how-do-we-type-pun-correctly
107 float resultAsFloat;
108 std::memcpy(&resultAsFloat, &resultAsUint, sizeof(float));
109 return resultAsFloat;
110 }
111
113 using UintType = std::make_unsigned_t<ElementType>;
114 UintType resultAsUint = 0;
115 for (size_t i = 0; i < bytes.size(); i++) {
116 resultAsUint |=
117 static_cast<UintType>(static_cast<UintType>(bytes[i]) << i * 8);
118 }
119
120 // Reinterpret the bits with the correct signedness.
121 return *reinterpret_cast<ElementType*>(&resultAsUint);
122 }
123}
124
132template <typename ElementType>
133ElementType assembleVecNValue(const std::span<uint8_t> bytes) noexcept {
134 ElementType result = ElementType();
135
136 [[maybe_unused]] constexpr glm::length_t N =
138 using T = typename ElementType::value_type;
139
140 CESIUM_ASSERT(
141 sizeof(T) <= 2 && "Components cannot be larger than two bytes in size.");
142
143 if constexpr (std::is_same_v<T, int16_t>) {
144 CESIUM_ASSERT(
145 N == 2 && "Only vec2s can contain two-byte integer components.");
146 uint16_t x = static_cast<uint16_t>(bytes[0]) |
147 static_cast<uint16_t>(static_cast<uint16_t>(bytes[1]) << 8);
148 uint16_t y = static_cast<uint16_t>(bytes[2]) |
149 static_cast<uint16_t>(static_cast<uint16_t>(bytes[3]) << 8);
150
151 result[0] = *reinterpret_cast<int16_t*>(&x);
152 result[1] = *reinterpret_cast<int16_t*>(&y);
153 }
154
155 if constexpr (std::is_same_v<T, uint16_t>) {
156 CESIUM_ASSERT(
157 N == 2 && "Only vec2s can contain two-byte integer components.");
158 result[0] = static_cast<uint16_t>(bytes[0]) |
159 static_cast<uint16_t>(static_cast<uint16_t>(bytes[1]) << 8);
160 result[1] = static_cast<uint16_t>(bytes[2]) |
161 static_cast<uint16_t>(static_cast<uint16_t>(bytes[3]) << 8);
162 }
163
164 if constexpr (std::is_same_v<T, int8_t>) {
165 for (size_t i = 0; i < bytes.size(); i++) {
166 result[int32_t(i)] = *reinterpret_cast<const int8_t*>(&bytes[i]);
167 }
168 }
169
170 if constexpr (std::is_same_v<T, uint8_t>) {
171 for (size_t i = 0; i < bytes.size(); i++) {
172 result[int32_t(i)] = bytes[i];
173 }
174 }
175
176 return result;
177}
178
186template <typename T>
187PropertyArrayCopy<T>
188assembleArrayValue(const std::span<uint8_t> bytes) noexcept {
189 std::vector<T> result(bytes.size() / sizeof(T));
190
191 if constexpr (sizeof(T) == 2) {
192 for (size_t i = 0, b = 0; i < result.size(); i++, b += 2) {
193 using UintType = std::make_unsigned_t<T>;
194 UintType resultAsUint =
195 static_cast<UintType>(bytes[b]) |
196 static_cast<UintType>(static_cast<UintType>(bytes[b + 1]) << 8);
197 result[i] = *reinterpret_cast<T*>(&resultAsUint);
198 }
199 } else {
200 for (size_t i = 0; i < bytes.size(); i++) {
201 result[i] = *reinterpret_cast<const T*>(&bytes[i]);
202 }
203 }
204
205 return PropertyArrayCopy<T>(std::move(result));
206}
207
217template <typename ElementType>
219assembleValueFromChannels(const std::span<uint8_t> bytes) noexcept {
220 CESIUM_ASSERT(
221 bytes.size() > 0 && "Channel input must have at least one value.");
222
225 }
226
228 return assembleVecNValue<ElementType>(bytes);
229 }
230
233 bytes);
234 }
235}
236
237#pragma region Non - normalized property
238
252template <typename ElementType, bool Normalized = false>
254
264template <typename ElementType>
265class PropertyTexturePropertyView<ElementType, false>
266 : public PropertyView<ElementType, false>, public TextureView {
267public:
272 : PropertyView<ElementType, false>(),
273 TextureView(),
274 _channels(),
275 _swizzle() {}
276
285 TextureView(),
286 _channels(),
287 _swizzle() {
288 CESIUM_ASSERT(
290 "An empty property view should not be constructed with a valid status");
291 }
292
300 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
301 : PropertyView<ElementType, false>(classProperty),
302 TextureView(),
303 _channels(),
304 _swizzle() {
306 // Don't override the status / size if something is wrong with the class
307 // property's definition.
308 return;
309 }
310
311 if (!classProperty.defaultProperty) {
312 // This constructor should only be called if the class property *has* a
313 // default value. But in the case that it does not, this property view
314 // becomes invalid.
315 this->_status =
317 return;
318 }
319
321 }
322
334 const PropertyTextureProperty& property,
335 const ClassProperty& classProperty,
336 const Sampler& sampler,
337 const CesiumImage::ImageAsset& image,
338 const TextureViewOptions& options = TextureViewOptions()) noexcept
339 : PropertyView<ElementType, false>(classProperty, property),
341 sampler,
342 image,
343 property.texCoord,
344 property.getExtension<ExtensionKhrTextureTransform>(),
345 options),
346 _channels(property.channels),
347 _swizzle() {
349 return;
350 }
351
352 switch (this->getTextureViewStatus()) {
354 break;
357 return;
360 return;
363 return;
365 this->_status =
367 return;
370 default:
372 return;
373 }
374
375 _swizzle.reserve(_channels.size());
376
377 for (size_t i = 0; i < _channels.size(); ++i) {
378 switch (_channels[i]) {
379 case 0:
380 _swizzle += "r";
381 break;
382 case 1:
383 _swizzle += "g";
384 break;
385 case 2:
386 _swizzle += "b";
387 break;
388 case 3:
389 _swizzle += "a";
390 break;
391 default:
392 CESIUM_ASSERT(
393 false && "A valid channels vector must be passed to the view.");
394 }
395 }
396 }
397
411 const PropertyTextureProperty& property,
412 const ClassProperty& classProperty,
413 const CesiumGltf::Enum* pEnumDefinition,
414 const Sampler& sampler,
415 const CesiumImage::ImageAsset& image,
416 const TextureViewOptions& options = TextureViewOptions()) noexcept
417 : PropertyView<ElementType, false>(
418 classProperty,
419 property,
420 pEnumDefinition),
422 sampler,
423 image,
424 property.texCoord,
425 property.getExtension<ExtensionKhrTextureTransform>(),
426 options),
427 _channels(property.channels),
428 _swizzle() {
430 return;
431 }
432
433 switch (this->getTextureViewStatus()) {
435 break;
438 return;
441 return;
444 return;
446 this->_status =
448 return;
451 default:
453 return;
454 }
455
456 _swizzle.reserve(_channels.size());
457
458 for (size_t i = 0; i < _channels.size(); ++i) {
459 switch (_channels[i]) {
460 case 0:
461 _swizzle += "r";
462 break;
463 case 1:
464 _swizzle += "g";
465 break;
466 case 2:
467 _swizzle += "b";
468 break;
469 case 3:
470 _swizzle += "a";
471 break;
472 default:
473 CESIUM_ASSERT(
474 false && "A valid channels vector must be passed to the view.");
475 }
476 }
477 }
478
496 std::optional<PropertyValueViewToCopy<ElementType>>
497 get(double u, double v) const noexcept {
498 if (this->_status ==
500 return propertyValueViewToCopy(this->defaultValue());
501 }
502
504
505 if (value == this->noData()) {
506 return propertyValueViewToCopy(this->defaultValue());
507 } else if constexpr (IsMetadataNumeric<ElementType>::value) {
508 return transformValue(value, this->offset(), this->scale());
509 } else if constexpr (IsMetadataNumericArray<ElementType>::value) {
510 return transformArray(
511 propertyValueCopyToView(value),
512 this->offset(),
513 this->scale());
514 } else {
515 return value;
516 }
517 }
518
532
534 getRaw(double u, double v) const noexcept {
535 CESIUM_ASSERT(
537 "Check the status() first to make sure view is valid");
538
539 std::vector<uint8_t> sample =
540 this->sampleNearestPixel(u, v, this->_channels);
541
543 std::span(sample.data(), this->_channels.size()));
544 }
545
549 const std::vector<int64_t>& getChannels() const noexcept {
550 return this->_channels;
551 }
552
556 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
557
558private:
559 std::vector<int64_t> _channels;
560 std::string _swizzle;
561};
562
563#pragma endregion
564
565#pragma region Normalized property
566
574template <typename ElementType>
575class PropertyTexturePropertyView<ElementType, true>
576 : public PropertyView<ElementType, true>, public TextureView {
577private:
578 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
579
580public:
585 : PropertyView<ElementType, true>(),
586 TextureView(),
587 _channels(),
588 _swizzle() {}
589
598 TextureView(),
599 _channels(),
600 _swizzle() {
601 CESIUM_ASSERT(
603 "An empty property view should not be constructed with a valid "
604 "status");
605 }
606
616 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
617 : PropertyView<ElementType, true>(classProperty),
618 TextureView(),
619 _channels(),
620 _swizzle() {
622 // Don't override the status / size if something is wrong with the class
623 // property's definition.
624 return;
625 }
626
627 if (!classProperty.defaultProperty) {
628 // This constructor should only be called if the class property *has* a
629 // default value. But in the case that it does not, this property view
630 // becomes invalid.
631 this->_status =
633 return;
634 }
635
637 }
638
650 const PropertyTextureProperty& property,
651 const ClassProperty& classProperty,
652 const Sampler& sampler,
653 const CesiumImage::ImageAsset& image,
654 const TextureViewOptions& options = TextureViewOptions()) noexcept
655 : PropertyView<ElementType, true>(classProperty, property),
657 sampler,
658 image,
659 property.texCoord,
660 property.getExtension<ExtensionKhrTextureTransform>(),
661 options),
662 _channels(property.channels),
663 _swizzle() {
665 return;
666 }
667
668 switch (this->getTextureViewStatus()) {
670 break;
673 return;
676 return;
679 return;
681 this->_status =
683 return;
686 default:
688 return;
689 }
690
691 _swizzle.reserve(_channels.size());
692 for (size_t i = 0; i < _channels.size(); ++i) {
693 switch (_channels[i]) {
694 case 0:
695 _swizzle += "r";
696 break;
697 case 1:
698 _swizzle += "g";
699 break;
700 case 2:
701 _swizzle += "b";
702 break;
703 case 3:
704 _swizzle += "a";
705 break;
706 default:
707 CESIUM_ASSERT(
708 false && "A valid channels vector must be passed to the view.");
709 }
710 }
711 }
712
731 std::optional<PropertyValueViewToCopy<NormalizedType>>
732 get(double u, double v) const noexcept {
733 if (this->_status ==
735 return propertyValueViewToCopy(this->defaultValue());
736 }
737
739
740 if (value == this->noData()) {
741 return propertyValueViewToCopy(this->defaultValue());
742 } else if constexpr (IsMetadataScalar<ElementType>::value) {
745 this->offset(),
746 this->scale());
747 } else if constexpr (IsMetadataVecN<ElementType>::value) {
748 constexpr glm::length_t N = ElementType::length();
749 using T = typename ElementType::value_type;
750 using NormalizedT = typename NormalizedType::value_type;
752 normalize<N, T>(value),
753 this->offset(),
754 this->scale());
755 } else if constexpr (IsMetadataArray<ElementType>::value) {
756 using ArrayElementType = typename MetadataArrayType<ElementType>::type;
759 propertyValueCopyToView(value),
760 this->offset(),
761 this->scale());
762 } else if constexpr (IsMetadataVecN<ArrayElementType>::value) {
763 constexpr glm::length_t N = ArrayElementType::length();
764 using T = typename ArrayElementType::value_type;
766 propertyValueCopyToView(value),
767 this->offset(),
768 this->scale());
769 }
770 }
771 }
772
786
788 getRaw(double u, double v) const noexcept {
789 CESIUM_ASSERT(
791 "Check the status() first to make sure view is valid");
792
793 std::vector<uint8_t> sample =
794 this->sampleNearestPixel(u, v, this->_channels);
795
797 std::span(sample.data(), this->_channels.size()));
798 }
799
803 const std::vector<int64_t>& getChannels() const noexcept {
804 return this->_channels;
805 }
806
810 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
811
812private:
813 std::vector<int64_t> _channels;
814 std::string _swizzle;
815};
816#pragma endregion
817
818} // namespace CesiumGltf
A copy of an array element of a PropertyTableProperty or PropertyTextureProperty.
Indicates the status of a property texture property view.
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 ErrorInvalidImage
This property view does not have a valid image index.
static const int ErrorInvalidChannels
The channels of this property texture property are invalid. Channels must be in the range 0-N,...
static const int ErrorInvalidBytesPerChannel
This property uses an image with multi-byte channels. Only single-byte channels are supported.
static const int ErrorInvalidSampler
This property view does not have a valid sampler index.
static const int ErrorInvalidPropertyTexture
This property view was initialized from an invalid PropertyTexture.
static const int ErrorInvalidTexture
This property view does not have a valid texture index.
static const int ErrorEmptyImage
This property is viewing an empty image.
PropertyTexturePropertyView(const PropertyTextureProperty &property, const ClassProperty &classProperty, const CesiumGltf::Enum *pEnumDefinition, const Sampler &sampler, const CesiumImage::ImageAsset &image, const TextureViewOptions &options=TextureViewOptions()) noexcept
Construct a view of the data specified by a PropertyTextureProperty.
const std::string & getSwizzle() const noexcept
Gets this property's channels as a swizzle string.
std::optional< PropertyValueViewToCopy< ElementType > > get(double u, double v) const noexcept
Gets the value of the property for the given texture coordinates with all value transforms applied....
PropertyTexturePropertyView(PropertyViewStatusType status) noexcept
Constructs an invalid instance for an erroneous property.
PropertyValueViewToCopy< ElementType > getRaw(double u, double v) const noexcept
Gets the raw value of the property for the given texture coordinates. The sampler's wrapping mode wil...
PropertyTexturePropertyView(const ClassProperty &classProperty) noexcept
Constructs an instance of an empty property that specifies a default value. Although this property ha...
PropertyTexturePropertyView(const PropertyTextureProperty &property, const ClassProperty &classProperty, const Sampler &sampler, const CesiumImage::ImageAsset &image, const TextureViewOptions &options=TextureViewOptions()) noexcept
Construct a view of the data specified by a PropertyTextureProperty.
PropertyTexturePropertyView() noexcept
Constructs an invalid instance for a non-existent property.
const std::vector< int64_t > & getChannels() const noexcept
Gets the channels of this property texture property.
PropertyValueViewToCopy< ElementType > getRaw(double u, double v) const noexcept
Gets the raw value of the property for the given texture coordinates. The sampler's wrapping mode wil...
PropertyTexturePropertyView(const ClassProperty &classProperty) noexcept
Constructs an instance of an empty property that specifies a default value. Although this property ha...
const std::string & getSwizzle() const noexcept
Gets this property's channels as a swizzle string.
PropertyTexturePropertyView() noexcept
Constructs an invalid instance for a non-existent property.
PropertyTexturePropertyView(const PropertyTextureProperty &property, const ClassProperty &classProperty, const Sampler &sampler, const CesiumImage::ImageAsset &image, const TextureViewOptions &options=TextureViewOptions()) noexcept
Construct a view of the data specified by a PropertyTextureProperty.
PropertyTexturePropertyView(PropertyViewStatusType status) noexcept
Constructs an invalid instance for an erroneous property.
std::optional< PropertyValueViewToCopy< NormalizedType > > get(double u, double v) const noexcept
Gets the value of the property for the given texture coordinates with all value transforms applied....
const std::vector< int64_t > & getChannels() const noexcept
Gets the channels of this property texture property.
A view of the data specified by a PropertyTextureProperty.
Indicates the status of a property view.
static const PropertyViewStatusType Valid
This property view is valid and ready to use.
static const PropertyViewStatusType ErrorNonexistentProperty
This property view is trying to view a property that does not exist.
static const PropertyViewStatusType EmptyPropertyWithDefault
This property view does not contain any data, but specifies a default value. This happens when a clas...
std::optional< ElementType > offset() const noexcept
Gets the offset to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the...
std::optional< ElementType > scale() const noexcept
Gets the scale to apply to property values. Only applicable to SCALAR, VECN, and MATN types when the ...
std::optional< ElementType > defaultValue() const noexcept
Gets the default value to use when encountering a "no data" value or an omitted property....
PropertyViewStatusType _status
Indicates the status of a property view.
PropertyViewStatusType status() const noexcept
Gets the status of this property view, indicating whether an error occurred.
std::optional< ElementType > noData() const noexcept
Gets the "no data" value, i.e., the value representing missing data in the property wherever it appea...
PropertyView()
Constructs an empty property instance.
std::optional< ElementType > noData() const noexcept
Constructs an empty property instance. false>noData
PropertyViewStatusType _status
Indicates the status of a property view.
std::optional< NormalizedType > scale() const noexcept
Constructs an empty property instance. false>scale
PropertyView()
Constructs an empty property instance.
std::optional< NormalizedType > defaultValue() const noexcept
Constructs an empty property instance. false>defaultValue
PropertyViewStatusType status() const noexcept
Constructs an empty property instance. false>status
std::optional< NormalizedType > offset() const noexcept
Constructs an empty property instance. false>offset
TextureViewStatus getTextureViewStatus() const noexcept
Get the status of this texture view.
TextureView() noexcept
Constructs an empty, uninitialized texture view.
std::vector< uint8_t > sampleNearestPixel(double u, double v, const std::vector< int64_t > &channels) const noexcept
Samples the image at the specified texture coordinates using NEAREST pixel filtering,...
Classes for working with glTF models.
PropertyArrayCopy< glm::vec< N, double > > transformNormalizedVecNArray(const PropertyArrayView< glm::vec< N, T > > &value, const std::optional< PropertyArrayView< glm::vec< N, double > > > &offset, const std::optional< PropertyArrayView< glm::vec< N, double > > > &scale)
Normalizes each element of an array of vectors and transforms them by optional offset and scale facto...
ElementType assembleVecNValue(const std::span< uint8_t > bytes) noexcept
Attempts to obtain a vector value from the given span of bytes.
PropertyArrayCopy< NormalizedType > transformNormalizedArray(const PropertyArrayView< T > &value, const std::optional< PropertyArrayView< NormalizedType > > &offset, const std::optional< PropertyArrayView< NormalizedType > > &scale)
Normalizes each element of an array of values and transforms them by optional offset and scale factor...
T transformValue(const T &value, const std::optional< T > &offset, const std::optional< T > &scale)
Transforms the value by optional offset and scale factors.
double normalize(T value)
Normalizes the given value between [0, 1] if unsigned or [-1, 1] if signed, based on the type's maxim...
@ ErrorEmptyImage
This texture is viewing an empty image.
Definition TextureView.h:86
@ ErrorUninitialized
This texture view has not yet been initialized.
Definition TextureView.h:66
@ Valid
This texture view is valid and ready to use.
Definition TextureView.h:61
@ ErrorInvalidSampler
This texture view does not have a valid sampler index.
Definition TextureView.h:76
@ ErrorInvalidImage
This texture view does not have a valid image index.
Definition TextureView.h:81
@ ErrorInvalidBytesPerChannel
The image for this texture has channels that take up more than a byte. Only single-byte channels are ...
Definition TextureView.h:92
@ ErrorInvalidTexture
This texture view does not have a valid texture index.
Definition TextureView.h:71
PropertyArrayCopy< T > transformArray(const PropertyArrayView< T > &value, const std::optional< PropertyArrayView< T > > &offset, const std::optional< PropertyArrayView< T > > &scale)
Transforms each element of an array of values by optional offset and scale factors....
std::conditional_t< IsMetadataNumericArray< T >::value, PropertyArrayCopy< typename MetadataArrayType< T >::type >, T > PropertyValueViewToCopy
Transforms a property value type from a view to an equivalent type that owns the data it is viewing....
ElementType assembleScalarValue(const std::span< uint8_t > bytes) noexcept
Attempts to obtain a scalar value from the given span of bytes.
PropertyArrayCopy< T > assembleArrayValue(const std::span< uint8_t > bytes) noexcept
Attempts to obtain an array value from the given span of bytes.
PropertyValueViewToCopy< ElementType > assembleValueFromChannels(const std::span< uint8_t > bytes) noexcept
Assembles the given type from the provided channel values of sampling a texture.
int32_t PropertyViewStatusType
The type used for fields of PropertyViewStatus.
std::optional< CesiumUtility::JsonValue > defaultProperty
A default value to use when encountering a noData value or an omitted property. The value is given in...
This class is not meant to be instantiated directly. Use Enum instead.
Definition Enum.h:12
glTF extension that enables shifting and scaling UV coordinates on a per-texture basis
Check if a C++ type can be represented as an array.
Check if a C++ type can be represented as an integer property type.
Check if a C++ type can be represented as an array of numeric elements property type.
Check if a C++ type can be represented as a numeric property, i.e. a scalar / vecN / matN type.
Check if a C++ type can be represented as a scalar property type.
Check if a C++ type can be represented as a vecN type.
void type
The component type of this metadata array.
A texture containing property values.
Texture sampler properties for filtering and wrapping modes.
Definition Sampler.h:14
Describes options for constructing a view on a glTF texture.
Definition TextureView.h:18
The number of dimensions that this type contains.
Convert an integer numeric type to the corresponding representation as a double type....
A 2D image asset, including its pixel data. The image may have mipmaps, and it may be encoded in a GP...
Definition ImageAsset.h:33