cesium-native 0.43.0
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
12#include <CesiumUtility/Assert.h>
13
14#include <array>
15#include <cmath>
16#include <cstdint>
17#include <optional>
18
19namespace CesiumGltf {
29public:
34 static const int ErrorInvalidPropertyTexture = 14;
35
40 static const int ErrorUnsupportedProperty = 15;
41
45 static const int ErrorInvalidTexture = 16;
46
50 static const int ErrorInvalidSampler = 17;
51
55 static const int ErrorInvalidImage = 18;
56
60 static const int ErrorEmptyImage = 19;
61
66 static const int ErrorInvalidBytesPerChannel = 20;
67
75 static const int ErrorInvalidChannels = 21;
76
83 static const int ErrorChannelsAndTypeMismatch = 22;
84};
85
93template <typename ElementType>
94ElementType assembleScalarValue(const std::span<uint8_t> bytes) noexcept {
95 if constexpr (std::is_same_v<ElementType, float>) {
96 CESIUM_ASSERT(
97 bytes.size() == sizeof(float) &&
98 "Not enough channel inputs to construct a float.");
99 uint32_t resultAsUint = 0;
100 for (size_t i = 0; i < bytes.size(); i++) {
101 resultAsUint |= static_cast<uint32_t>(bytes[i]) << i * 8;
102 }
103
104 // Reinterpret the bits as a float.
105 return *reinterpret_cast<float*>(&resultAsUint);
106 }
107
109 using UintType = std::make_unsigned_t<ElementType>;
110 UintType resultAsUint = 0;
111 for (size_t i = 0; i < bytes.size(); i++) {
112 resultAsUint |= static_cast<UintType>(bytes[i]) << i * 8;
113 }
114
115 // Reinterpret the bits with the correct signedness.
116 return *reinterpret_cast<ElementType*>(&resultAsUint);
117 }
118}
119
127template <typename ElementType>
128ElementType assembleVecNValue(const std::span<uint8_t> bytes) noexcept {
129 ElementType result = ElementType();
130
131 const glm::length_t N =
133 using T = typename ElementType::value_type;
134
135 CESIUM_ASSERT(
136 sizeof(T) <= 2 && "Components cannot be larger than two bytes in size.");
137
138 if constexpr (std::is_same_v<T, int16_t>) {
139 CESIUM_ASSERT(
140 N == 2 && "Only vec2s can contain two-byte integer components.");
141 uint16_t x = static_cast<uint16_t>(bytes[0]) |
142 (static_cast<uint16_t>(bytes[1]) << 8);
143 uint16_t y = static_cast<uint16_t>(bytes[2]) |
144 (static_cast<uint16_t>(bytes[3]) << 8);
145
146 result[0] = *reinterpret_cast<int16_t*>(&x);
147 result[1] = *reinterpret_cast<int16_t*>(&y);
148 }
149
150 if constexpr (std::is_same_v<T, uint16_t>) {
151 CESIUM_ASSERT(
152 N == 2 && "Only vec2s can contain two-byte integer components.");
153 result[0] = static_cast<uint16_t>(bytes[0]) |
154 (static_cast<uint16_t>(bytes[1]) << 8);
155 result[1] = static_cast<uint16_t>(bytes[2]) |
156 (static_cast<uint16_t>(bytes[3]) << 8);
157 }
158
159 if constexpr (std::is_same_v<T, int8_t>) {
160 for (size_t i = 0; i < bytes.size(); i++) {
161 result[i] = *reinterpret_cast<const int8_t*>(&bytes[i]);
162 }
163 }
164
165 if constexpr (std::is_same_v<T, uint8_t>) {
166 for (size_t i = 0; i < bytes.size(); i++) {
167 result[i] = bytes[i];
168 }
169 }
170
171 return result;
172}
173
181template <typename T>
182PropertyArrayCopy<T>
183assembleArrayValue(const std::span<uint8_t> bytes) noexcept {
184 std::vector<T> result(bytes.size() / sizeof(T));
185
186 if constexpr (sizeof(T) == 2) {
187 for (int i = 0, b = 0; i < result.size(); i++, b += 2) {
188 using UintType = std::make_unsigned_t<T>;
189 UintType resultAsUint = static_cast<UintType>(bytes[b]) |
190 (static_cast<UintType>(bytes[b + 1]) << 8);
191 result[i] = *reinterpret_cast<T*>(&resultAsUint);
192 }
193 } else {
194 for (size_t i = 0; i < bytes.size(); i++) {
195 result[i] = *reinterpret_cast<const T*>(&bytes[i]);
196 }
197 }
198
199 return PropertyArrayCopy<T>(std::move(result));
200}
201
211template <typename ElementType>
213assembleValueFromChannels(const std::span<uint8_t> bytes) noexcept {
214 CESIUM_ASSERT(
215 bytes.size() > 0 && "Channel input must have at least one value.");
216
219 }
220
222 return assembleVecNValue<ElementType>(bytes);
223 }
224
226 return assembleArrayValue<typename MetadataArrayType<ElementType>::type>(
227 bytes);
228 }
229}
230
231#pragma region Non - normalized property
232
246template <typename ElementType, bool Normalized = false>
248
258template <typename ElementType>
259class PropertyTexturePropertyView<ElementType, false>
260 : public PropertyView<ElementType, false>, public TextureView {
261public:
266 : PropertyView<ElementType, false>(),
267 TextureView(),
268 _channels(),
269 _swizzle() {}
270
278 TextureView(),
279 _channels(),
280 _swizzle() {
281 CESIUM_ASSERT(
283 "An empty property view should not be constructed with a valid status");
284 }
285
293 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
294 : PropertyView<ElementType, false>(classProperty),
295 TextureView(),
296 _channels(),
297 _swizzle() {
298 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
299 // Don't override the status / size if something is wrong with the class
300 // property's definition.
301 return;
302 }
303
304 if (!classProperty.defaultProperty) {
305 // This constructor should only be called if the class property *has* a
306 // default value. But in the case that it does not, this property view
307 // becomes invalid.
308 this->_status =
310 return;
311 }
312
314 }
315
326 const PropertyTextureProperty& property,
327 const ClassProperty& classProperty,
328 const Sampler& sampler,
329 const ImageAsset& image,
330 const TextureViewOptions& options = TextureViewOptions()) noexcept
331 : PropertyView<ElementType, false>(classProperty, property),
333 sampler,
334 image,
335 property.texCoord,
336 property.getExtension<ExtensionKhrTextureTransform>(),
337 options),
338 _channels(property.channels),
339 _swizzle() {
340 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
341 return;
342 }
343
344 switch (this->getTextureViewStatus()) {
346 break;
349 return;
352 return;
355 return;
357 this->_status =
359 return;
362 default:
364 return;
365 }
366
367 _swizzle.reserve(_channels.size());
368
369 for (size_t i = 0; i < _channels.size(); ++i) {
370 switch (_channels[i]) {
371 case 0:
372 _swizzle += "r";
373 break;
374 case 1:
375 _swizzle += "g";
376 break;
377 case 2:
378 _swizzle += "b";
379 break;
380 case 3:
381 _swizzle += "a";
382 break;
383 default:
384 CESIUM_ASSERT(
385 false && "A valid channels vector must be passed to the view.");
386 }
387 }
388 }
389
407 std::optional<PropertyValueViewToCopy<ElementType>>
408 get(double u, double v) const noexcept {
409 if (this->_status ==
411 return propertyValueViewToCopy(this->defaultValue());
412 }
413
414 PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
415
416 if (value == this->noData()) {
417 return propertyValueViewToCopy(this->defaultValue());
418 } else if constexpr (IsMetadataNumeric<ElementType>::value) {
419 return transformValue(value, this->offset(), this->scale());
420 } else if constexpr (IsMetadataNumericArray<ElementType>::value) {
421 return transformArray(
422 propertyValueCopyToView(value),
423 this->offset(),
424 this->scale());
425 } else {
426 return value;
427 }
428 }
429
445 getRaw(double u, double v) const noexcept {
446 CESIUM_ASSERT(
448 "Check the status() first to make sure view is valid");
449
450 std::vector<uint8_t> sample =
451 this->sampleNearestPixel(u, v, this->_channels);
452
454 std::span(sample.data(), this->_channels.size()));
455 }
456
460 const std::vector<int64_t>& getChannels() const noexcept {
461 return this->_channels;
462 }
463
467 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
468
469private:
470 std::vector<int64_t> _channels;
471 std::string _swizzle;
472};
473
474#pragma endregion
475
476#pragma region Normalized property
477
485template <typename ElementType>
486class PropertyTexturePropertyView<ElementType, true>
487 : public PropertyView<ElementType, true>, public TextureView {
488private:
489 using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
490
491public:
496 : PropertyView<ElementType, true>(),
497 TextureView(),
498 _channels(),
499 _swizzle() {}
500
508 TextureView(),
509 _channels(),
510 _swizzle() {
511 CESIUM_ASSERT(
513 "An empty property view should not be constructed with a valid "
514 "status");
515 }
516
525 PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
526 : PropertyView<ElementType, true>(classProperty),
527 TextureView(),
528 _channels(),
529 _swizzle() {
530 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
531 // Don't override the status / size if something is wrong with the class
532 // property's definition.
533 return;
534 }
535
536 if (!classProperty.defaultProperty) {
537 // This constructor should only be called if the class property *has* a
538 // default value. But in the case that it does not, this property view
539 // becomes invalid.
540 this->_status =
542 return;
543 }
544
546 }
547
558 const PropertyTextureProperty& property,
559 const ClassProperty& classProperty,
560 const Sampler& sampler,
561 const ImageAsset& image,
562 const TextureViewOptions& options = TextureViewOptions()) noexcept
563 : PropertyView<ElementType, true>(classProperty, property),
565 sampler,
566 image,
567 property.texCoord,
568 property.getExtension<ExtensionKhrTextureTransform>(),
569 options),
570 _channels(property.channels),
571 _swizzle() {
572 if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
573 return;
574 }
575
576 switch (this->getTextureViewStatus()) {
578 break;
581 return;
584 return;
587 return;
589 this->_status =
591 return;
594 default:
596 return;
597 }
598
599 _swizzle.reserve(_channels.size());
600 for (size_t i = 0; i < _channels.size(); ++i) {
601 switch (_channels[i]) {
602 case 0:
603 _swizzle += "r";
604 break;
605 case 1:
606 _swizzle += "g";
607 break;
608 case 2:
609 _swizzle += "b";
610 break;
611 case 3:
612 _swizzle += "a";
613 break;
614 default:
615 CESIUM_ASSERT(
616 false && "A valid channels vector must be passed to the view.");
617 }
618 }
619 }
620
639 std::optional<PropertyValueViewToCopy<NormalizedType>>
640 get(double u, double v) const noexcept {
641 if (this->_status ==
643 return propertyValueViewToCopy(this->defaultValue());
644 }
645
646 PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
647
648 if (value == this->noData()) {
649 return propertyValueViewToCopy(this->defaultValue());
650 } else if constexpr (IsMetadataScalar<ElementType>::value) {
653 this->offset(),
654 this->scale());
655 } else if constexpr (IsMetadataVecN<ElementType>::value) {
656 constexpr glm::length_t N = ElementType::length();
657 using T = typename ElementType::value_type;
658 using NormalizedT = typename NormalizedType::value_type;
660 normalize<N, T>(value),
661 this->offset(),
662 this->scale());
663 } else if constexpr (IsMetadataArray<ElementType>::value) {
664 using ArrayElementType = typename MetadataArrayType<ElementType>::type;
667 propertyValueCopyToView(value),
668 this->offset(),
669 this->scale());
670 } else if constexpr (IsMetadataVecN<ArrayElementType>::value) {
671 constexpr glm::length_t N = ArrayElementType::length();
672 using T = typename ArrayElementType::value_type;
674 propertyValueCopyToView(value),
675 this->offset(),
676 this->scale());
677 }
678 }
679 }
680
696 getRaw(double u, double v) const noexcept {
697 CESIUM_ASSERT(
699 "Check the status() first to make sure view is valid");
700
701 std::vector<uint8_t> sample =
702 this->sampleNearestPixel(u, v, this->_channels);
703
705 std::span(sample.data(), this->_channels.size()));
706 }
707
711 const std::vector<int64_t>& getChannels() const noexcept {
712 return this->_channels;
713 }
714
718 const std::string& getSwizzle() const noexcept { return this->_swizzle; }
719
720private:
721 std::vector<int64_t> _channels;
722 std::string _swizzle;
723};
724#pragma endregion
725
726} // 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.