cesium-native 0.44.2
Loading...
Searching...
No Matches
PropertyTexturePropertyView.h
1#pragma once
2
3#include <CesiumGltf/ImageAsset.h>
4#include <CesiumGltf/KhrTextureTransform.h>
5#include <CesiumGltf/PropertyTextureProperty.h>
6#include <CesiumGltf/PropertyTransformations.h>
7#include <CesiumGltf/PropertyTypeTraits.h>
8#include <CesiumGltf/PropertyView.h>
9#include <CesiumGltf/Sampler.h>
10#include <CesiumGltf/TextureView.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 = 14;
34
39 static const int ErrorUnsupportedProperty = 15;
40
44 static const int ErrorInvalidTexture = 16;
45
49 static const int ErrorInvalidSampler = 17;
50
54 static const int ErrorInvalidImage = 18;
55
59 static const int ErrorEmptyImage = 19;
60
65 static const int ErrorInvalidBytesPerChannel = 20;
66
74 static const int ErrorInvalidChannels = 21;
75
82 static const int ErrorChannelsAndTypeMismatch = 22;
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 return *reinterpret_cast<float*>(&resultAsUint);
105 }
106
108 using UintType = std::make_unsigned_t<ElementType>;
109 UintType resultAsUint = 0;
110 for (size_t i = 0; i < bytes.size(); i++) {
111 resultAsUint |= static_cast<UintType>(bytes[i]) << i * 8;
112 }
113
114 // Reinterpret the bits with the correct signedness.
115 return *reinterpret_cast<ElementType*>(&resultAsUint);
116 }
117}
118
126template <typename ElementType>
127ElementType assembleVecNValue(const std::span<uint8_t> bytes) noexcept {
128 ElementType result = ElementType();
129
130 const glm::length_t N =
132 using T = typename ElementType::value_type;
133
134 CESIUM_ASSERT(
135 sizeof(T) <= 2 && "Components cannot be larger than two bytes in size.");
136
137 if constexpr (std::is_same_v<T, int16_t>) {
138 CESIUM_ASSERT(
139 N == 2 && "Only vec2s can contain two-byte integer components.");
140 uint16_t x = static_cast<uint16_t>(bytes[0]) |
141 (static_cast<uint16_t>(bytes[1]) << 8);
142 uint16_t y = static_cast<uint16_t>(bytes[2]) |
143 (static_cast<uint16_t>(bytes[3]) << 8);
144
145 result[0] = *reinterpret_cast<int16_t*>(&x);
146 result[1] = *reinterpret_cast<int16_t*>(&y);
147 }
148
149 if constexpr (std::is_same_v<T, uint16_t>) {
150 CESIUM_ASSERT(
151 N == 2 && "Only vec2s can contain two-byte integer components.");
152 result[0] = static_cast<uint16_t>(bytes[0]) |
153 (static_cast<uint16_t>(bytes[1]) << 8);
154 result[1] = static_cast<uint16_t>(bytes[2]) |
155 (static_cast<uint16_t>(bytes[3]) << 8);
156 }
157
158 if constexpr (std::is_same_v<T, int8_t>) {
159 for (size_t i = 0; i < bytes.size(); i++) {
160 result[i] = *reinterpret_cast<const int8_t*>(&bytes[i]);
161 }
162 }
163
164 if constexpr (std::is_same_v<T, uint8_t>) {
165 for (size_t i = 0; i < bytes.size(); i++) {
166 result[i] = bytes[i];
167 }
168 }
169
170 return result;
171}
172
180template <typename T>
181PropertyArrayCopy<T>
182assembleArrayValue(const std::span<uint8_t> bytes) noexcept {
183 std::vector<T> result(bytes.size() / sizeof(T));
184
185 if constexpr (sizeof(T) == 2) {
186 for (int i = 0, b = 0; i < result.size(); i++, b += 2) {
187 using UintType = std::make_unsigned_t<T>;
188 UintType resultAsUint = static_cast<UintType>(bytes[b]) |
189 (static_cast<UintType>(bytes[b + 1]) << 8);
190 result[i] = *reinterpret_cast<T*>(&resultAsUint);
191 }
192 } else {
193 for (size_t i = 0; i < bytes.size(); i++) {
194 result[i] = *reinterpret_cast<const T*>(&bytes[i]);
195 }
196 }
197
198 return PropertyArrayCopy<T>(std::move(result));
199}
200
210template <typename ElementType>
212assembleValueFromChannels(const std::span<uint8_t> bytes) noexcept {
213 CESIUM_ASSERT(
214 bytes.size() > 0 && "Channel input must have at least one value.");
215
218 }
219
221 return assembleVecNValue<ElementType>(bytes);
222 }
223
225 return assembleArrayValue<typename MetadataArrayType<ElementType>::type>(
226 bytes);
227 }
228}
229
230#pragma region Non - normalized property
231
245template <typename ElementType, bool Normalized = false>
247
257template <typename ElementType>
258class PropertyTexturePropertyView<ElementType, false>
259 : public PropertyView<ElementType, false>, public TextureView {
260public:
265 : PropertyView<ElementType, false>(),
266 TextureView(),
267 _channels(),
268 _swizzle() {}
269
277 TextureView(),
278 _channels(),
279 _swizzle() {
280 CESIUM_ASSERT(
282 "An empty property view should not be constructed with a valid status");
283 }
284
292 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
293 : PropertyView<ElementType, false>(classProperty),
294 TextureView(),
295 _channels(),
296 _swizzle() {
297 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
298 // Don't override the status / size if something is wrong with the class
299 // property's definition.
300 return;
301 }
302
303 if (!classProperty.defaultProperty) {
304 // This constructor should only be called if the class property *has* a
305 // default value. But in the case that it does not, this property view
306 // becomes invalid.
307 this->_status =
309 return;
310 }
311
313 }
314
325 const PropertyTextureProperty& property,
326 const ClassProperty& classProperty,
327 const Sampler& sampler,
328 const ImageAsset& image,
329 const TextureViewOptions& options = TextureViewOptions()) noexcept
330 : PropertyView<ElementType, false>(classProperty, property),
332 sampler,
333 image,
334 property.texCoord,
335 property.getExtension<ExtensionKhrTextureTransform>(),
336 options),
337 _channels(property.channels),
338 _swizzle() {
339 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
340 return;
341 }
342
343 switch (this->getTextureViewStatus()) {
345 break;
348 return;
351 return;
354 return;
356 this->_status =
358 return;
361 default:
363 return;
364 }
365
366 _swizzle.reserve(_channels.size());
367
368 for (size_t i = 0; i < _channels.size(); ++i) {
369 switch (_channels[i]) {
370 case 0:
371 _swizzle += "r";
372 break;
373 case 1:
374 _swizzle += "g";
375 break;
376 case 2:
377 _swizzle += "b";
378 break;
379 case 3:
380 _swizzle += "a";
381 break;
382 default:
383 CESIUM_ASSERT(
384 false && "A valid channels vector must be passed to the view.");
385 }
386 }
387 }
388
406 std::optional<PropertyValueViewToCopy<ElementType>>
407 get(double u, double v) const noexcept {
408 if (this->_status ==
410 return propertyValueViewToCopy(this->defaultValue());
411 }
412
413 PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
414
415 if (value == this->noData()) {
416 return propertyValueViewToCopy(this->defaultValue());
417 } else if constexpr (IsMetadataNumeric<ElementType>::value) {
418 return transformValue(value, this->offset(), this->scale());
419 } else if constexpr (IsMetadataNumericArray<ElementType>::value) {
420 return transformArray(
421 propertyValueCopyToView(value),
422 this->offset(),
423 this->scale());
424 } else {
425 return value;
426 }
427 }
428
444 getRaw(double u, double v) const noexcept {
445 CESIUM_ASSERT(
447 "Check the status() first to make sure view is valid");
448
449 std::vector<uint8_t> sample =
450 this->sampleNearestPixel(u, v, this->_channels);
451
453 std::span(sample.data(), this->_channels.size()));
454 }
455
459 const std::vector<int64_t>& getChannels() const noexcept {
460 return this->_channels;
461 }
462
466 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
467
468private:
469 std::vector<int64_t> _channels;
470 std::string _swizzle;
471};
472
473#pragma endregion
474
475#pragma region Normalized property
476
484template <typename ElementType>
485class PropertyTexturePropertyView<ElementType, true>
486 : public PropertyView<ElementType, true>, public TextureView {
487private:
488 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
489
490public:
495 : PropertyView<ElementType, true>(),
496 TextureView(),
497 _channels(),
498 _swizzle() {}
499
507 TextureView(),
508 _channels(),
509 _swizzle() {
510 CESIUM_ASSERT(
512 "An empty property view should not be constructed with a valid "
513 "status");
514 }
515
524 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
525 : PropertyView<ElementType, true>(classProperty),
526 TextureView(),
527 _channels(),
528 _swizzle() {
529 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
530 // Don't override the status / size if something is wrong with the class
531 // property's definition.
532 return;
533 }
534
535 if (!classProperty.defaultProperty) {
536 // This constructor should only be called if the class property *has* a
537 // default value. But in the case that it does not, this property view
538 // becomes invalid.
539 this->_status =
541 return;
542 }
543
545 }
546
557 const PropertyTextureProperty& property,
558 const ClassProperty& classProperty,
559 const Sampler& sampler,
560 const ImageAsset& image,
561 const TextureViewOptions& options = TextureViewOptions()) noexcept
562 : PropertyView<ElementType, true>(classProperty, property),
564 sampler,
565 image,
566 property.texCoord,
567 property.getExtension<ExtensionKhrTextureTransform>(),
568 options),
569 _channels(property.channels),
570 _swizzle() {
571 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
572 return;
573 }
574
575 switch (this->getTextureViewStatus()) {
577 break;
580 return;
583 return;
586 return;
588 this->_status =
590 return;
593 default:
595 return;
596 }
597
598 _swizzle.reserve(_channels.size());
599 for (size_t i = 0; i < _channels.size(); ++i) {
600 switch (_channels[i]) {
601 case 0:
602 _swizzle += "r";
603 break;
604 case 1:
605 _swizzle += "g";
606 break;
607 case 2:
608 _swizzle += "b";
609 break;
610 case 3:
611 _swizzle += "a";
612 break;
613 default:
614 CESIUM_ASSERT(
615 false && "A valid channels vector must be passed to the view.");
616 }
617 }
618 }
619
638 std::optional<PropertyValueViewToCopy<NormalizedType>>
639 get(double u, double v) const noexcept {
640 if (this->_status ==
642 return propertyValueViewToCopy(this->defaultValue());
643 }
644
645 PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
646
647 if (value == this->noData()) {
648 return propertyValueViewToCopy(this->defaultValue());
649 } else if constexpr (IsMetadataScalar<ElementType>::value) {
652 this->offset(),
653 this->scale());
654 } else if constexpr (IsMetadataVecN<ElementType>::value) {
655 constexpr glm::length_t N = ElementType::length();
656 using T = typename ElementType::value_type;
657 using NormalizedT = typename NormalizedType::value_type;
659 normalize<N, T>(value),
660 this->offset(),
661 this->scale());
662 } else if constexpr (IsMetadataArray<ElementType>::value) {
663 using ArrayElementType = typename MetadataArrayType<ElementType>::type;
666 propertyValueCopyToView(value),
667 this->offset(),
668 this->scale());
669 } else if constexpr (IsMetadataVecN<ArrayElementType>::value) {
670 constexpr glm::length_t N = ArrayElementType::length();
671 using T = typename ArrayElementType::value_type;
673 propertyValueCopyToView(value),
674 this->offset(),
675 this->scale());
676 }
677 }
678 }
679
695 getRaw(double u, double v) const noexcept {
696 CESIUM_ASSERT(
698 "Check the status() first to make sure view is valid");
699
700 std::vector<uint8_t> sample =
701 this->sampleNearestPixel(u, v, this->_channels);
702
704 std::span(sample.data(), this->_channels.size()));
705 }
706
710 const std::vector<int64_t>& getChannels() const noexcept {
711 return this->_channels;
712 }
713
717 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
718
719private:
720 std::vector<int64_t> _channels;
721 std::string _swizzle;
722};
723#pragma endregion
724
725} // 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.
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() noexcept
Constructs an invalid instance for a non-existent property.
PropertyTexturePropertyView(const PropertyTextureProperty &property, const ClassProperty &classProperty, const Sampler &sampler, const ImageAsset &image, const TextureViewOptions &options=TextureViewOptions()) noexcept
Construct a view of the data specified by a PropertyTextureProperty.
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(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....
PropertyTexturePropertyView(const PropertyTextureProperty &property, const ClassProperty &classProperty, const Sampler &sampler, const ImageAsset &image, const TextureViewOptions &options=TextureViewOptions()) noexcept
Construct a view of the data specified by a PropertyTextureProperty.
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...
Represents a metadata property in EXT_structural_metadata.
A view into the texture data of a single texture from a Model.
Definition TextureView.h:98
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.
@ ErrorUninitialized
This texture view has not yet been initialized.
@ Valid
This texture view is valid and ready to use.
@ ErrorInvalidSampler
This texture view does not have a valid sampler index.
@ ErrorInvalidImage
This texture view does not have a valid image index.
@ ErrorInvalidBytesPerChannel
The image for this texture has channels that take up more than a byte. Only single-byte channels are ...
@ ErrorInvalidTexture
This texture view does not have a valid texture index.
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.
glm::length_t getDimensionsFromPropertyType(PropertyType type)
Obtains the number of dimensions in the given PropertyType.
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.
glTF extension that enables shifting and scaling UV coordinates on a per-texture basis
A 2D image asset, including its pixel data. The image may have mipmaps, and it may be encoded in a GP...
Definition ImageAsset.h:34
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
Convert an integer numeric type to the corresponding representation as a double type....
Convert a C++ type to PropertyType and PropertyComponentType.