cesium-native 0.62.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
284 TextureView(),
285 _channels(),
286 _swizzle() {
287 CESIUM_ASSERT(
289 "An empty property view should not be constructed with a valid status");
290 }
291
299 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
300 : PropertyView<ElementType, false>(classProperty),
301 TextureView(),
302 _channels(),
303 _swizzle() {
305 // Don't override the status / size if something is wrong with the class
306 // property's definition.
307 return;
308 }
309
310 if (!classProperty.defaultProperty) {
311 // This constructor should only be called if the class property *has* a
312 // default value. But in the case that it does not, this property view
313 // becomes invalid.
314 this->_status =
316 return;
317 }
318
320 }
321
333 const PropertyTextureProperty& property,
334 const ClassProperty& classProperty,
335 const Sampler& sampler,
336 const CesiumImage::ImageAsset& image,
337 const TextureViewOptions& options = TextureViewOptions()) noexcept
338 : PropertyView<ElementType, false>(classProperty, property),
340 sampler,
341 image,
342 property.texCoord,
343 property.getExtension<ExtensionKhrTextureTransform>(),
344 options),
345 _channels(property.channels),
346 _swizzle() {
348 return;
349 }
350
351 switch (this->getTextureViewStatus()) {
353 break;
356 return;
359 return;
362 return;
364 this->_status =
366 return;
369 default:
371 return;
372 }
373
374 _swizzle.reserve(_channels.size());
375
376 for (size_t i = 0; i < _channels.size(); ++i) {
377 switch (_channels[i]) {
378 case 0:
379 _swizzle += "r";
380 break;
381 case 1:
382 _swizzle += "g";
383 break;
384 case 2:
385 _swizzle += "b";
386 break;
387 case 3:
388 _swizzle += "a";
389 break;
390 default:
391 CESIUM_ASSERT(
392 false && "A valid channels vector must be passed to the view.");
393 }
394 }
395 }
396
410 const PropertyTextureProperty& property,
411 const ClassProperty& classProperty,
412 const CesiumGltf::Enum* pEnumDefinition,
413 const Sampler& sampler,
414 const CesiumImage::ImageAsset& image,
415 const TextureViewOptions& options = TextureViewOptions()) noexcept
416 : PropertyView<ElementType, false>(
417 classProperty,
418 property,
419 pEnumDefinition),
421 sampler,
422 image,
423 property.texCoord,
424 property.getExtension<ExtensionKhrTextureTransform>(),
425 options),
426 _channels(property.channels),
427 _swizzle() {
429 return;
430 }
431
432 switch (this->getTextureViewStatus()) {
434 break;
437 return;
440 return;
443 return;
445 this->_status =
447 return;
450 default:
452 return;
453 }
454
455 _swizzle.reserve(_channels.size());
456
457 for (size_t i = 0; i < _channels.size(); ++i) {
458 switch (_channels[i]) {
459 case 0:
460 _swizzle += "r";
461 break;
462 case 1:
463 _swizzle += "g";
464 break;
465 case 2:
466 _swizzle += "b";
467 break;
468 case 3:
469 _swizzle += "a";
470 break;
471 default:
472 CESIUM_ASSERT(
473 false && "A valid channels vector must be passed to the view.");
474 }
475 }
476 }
477
495 std::optional<PropertyValueViewToCopy<ElementType>>
496 get(double u, double v) const noexcept {
497 if (this->_status ==
499 return propertyValueViewToCopy(this->defaultValue());
500 }
501
503
504 if (value == this->noData()) {
505 return propertyValueViewToCopy(this->defaultValue());
506 } else if constexpr (IsMetadataNumeric<ElementType>::value) {
507 return transformValue(value, this->offset(), this->scale());
508 } else if constexpr (IsMetadataNumericArray<ElementType>::value) {
509 return transformArray(
510 propertyValueCopyToView(value),
511 this->offset(),
512 this->scale());
513 } else {
514 return value;
515 }
516 }
517
531
533 getRaw(double u, double v) const noexcept {
534 CESIUM_ASSERT(
536 "Check the status() first to make sure view is valid");
537
538 std::vector<uint8_t> sample =
539 this->sampleNearestPixel(u, v, this->_channels);
540
542 std::span(sample.data(), this->_channels.size()));
543 }
544
548 const std::vector<int64_t>& getChannels() const noexcept {
549 return this->_channels;
550 }
551
555 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
556
557private:
558 std::vector<int64_t> _channels;
559 std::string _swizzle;
560};
561
562#pragma endregion
563
564#pragma region Normalized property
565
573template <typename ElementType>
574class PropertyTexturePropertyView<ElementType, true>
575 : public PropertyView<ElementType, true>, public TextureView {
576private:
577 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
578
579public:
584 : PropertyView<ElementType, true>(),
585 TextureView(),
586 _channels(),
587 _swizzle() {}
588
596 TextureView(),
597 _channels(),
598 _swizzle() {
599 CESIUM_ASSERT(
601 "An empty property view should not be constructed with a valid "
602 "status");
603 }
604
613 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
614 : PropertyView<ElementType, true>(classProperty),
615 TextureView(),
616 _channels(),
617 _swizzle() {
619 // Don't override the status / size if something is wrong with the class
620 // property's definition.
621 return;
622 }
623
624 if (!classProperty.defaultProperty) {
625 // This constructor should only be called if the class property *has* a
626 // default value. But in the case that it does not, this property view
627 // becomes invalid.
628 this->_status =
630 return;
631 }
632
634 }
635
647 const PropertyTextureProperty& property,
648 const ClassProperty& classProperty,
649 const Sampler& sampler,
650 const CesiumImage::ImageAsset& image,
651 const TextureViewOptions& options = TextureViewOptions()) noexcept
652 : PropertyView<ElementType, true>(classProperty, property),
654 sampler,
655 image,
656 property.texCoord,
657 property.getExtension<ExtensionKhrTextureTransform>(),
658 options),
659 _channels(property.channels),
660 _swizzle() {
662 return;
663 }
664
665 switch (this->getTextureViewStatus()) {
667 break;
670 return;
673 return;
676 return;
678 this->_status =
680 return;
683 default:
685 return;
686 }
687
688 _swizzle.reserve(_channels.size());
689 for (size_t i = 0; i < _channels.size(); ++i) {
690 switch (_channels[i]) {
691 case 0:
692 _swizzle += "r";
693 break;
694 case 1:
695 _swizzle += "g";
696 break;
697 case 2:
698 _swizzle += "b";
699 break;
700 case 3:
701 _swizzle += "a";
702 break;
703 default:
704 CESIUM_ASSERT(
705 false && "A valid channels vector must be passed to the view.");
706 }
707 }
708 }
709
728 std::optional<PropertyValueViewToCopy<NormalizedType>>
729 get(double u, double v) const noexcept {
730 if (this->_status ==
732 return propertyValueViewToCopy(this->defaultValue());
733 }
734
736
737 if (value == this->noData()) {
738 return propertyValueViewToCopy(this->defaultValue());
739 } else if constexpr (IsMetadataScalar<ElementType>::value) {
742 this->offset(),
743 this->scale());
744 } else if constexpr (IsMetadataVecN<ElementType>::value) {
745 constexpr glm::length_t N = ElementType::length();
746 using T = typename ElementType::value_type;
747 using NormalizedT = typename NormalizedType::value_type;
749 normalize<N, T>(value),
750 this->offset(),
751 this->scale());
752 } else if constexpr (IsMetadataArray<ElementType>::value) {
753 using ArrayElementType = typename MetadataArrayType<ElementType>::type;
756 propertyValueCopyToView(value),
757 this->offset(),
758 this->scale());
759 } else if constexpr (IsMetadataVecN<ArrayElementType>::value) {
760 constexpr glm::length_t N = ArrayElementType::length();
761 using T = typename ArrayElementType::value_type;
763 propertyValueCopyToView(value),
764 this->offset(),
765 this->scale());
766 }
767 }
768 }
769
783
785 getRaw(double u, double v) const noexcept {
786 CESIUM_ASSERT(
788 "Check the status() first to make sure view is valid");
789
790 std::vector<uint8_t> sample =
791 this->sampleNearestPixel(u, v, this->_channels);
792
794 std::span(sample.data(), this->_channels.size()));
795 }
796
800 const std::vector<int64_t>& getChannels() const noexcept {
801 return this->_channels;
802 }
803
807 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
808
809private:
810 std::vector<int64_t> _channels;
811 std::string _swizzle;
812};
813#pragma endregion
814
815} // 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