727 lines
24 KiB
C++
727 lines
24 KiB
C++
#pragma once
|
|
|
|
#include "CesiumGltf/ImageAsset.h"
|
|
#include "CesiumGltf/KhrTextureTransform.h"
|
|
#include "CesiumGltf/PropertyTextureProperty.h"
|
|
#include "CesiumGltf/PropertyTransformations.h"
|
|
#include "CesiumGltf/PropertyTypeTraits.h"
|
|
#include "CesiumGltf/PropertyView.h"
|
|
#include "CesiumGltf/Sampler.h"
|
|
#include "CesiumGltf/TextureView.h"
|
|
|
|
#include <CesiumUtility/Assert.h>
|
|
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
|
|
namespace CesiumGltf {
|
|
/**
|
|
* @brief Indicates the status of a property texture property view.
|
|
*
|
|
* The {@link PropertyTexturePropertyView} constructor always completes
|
|
* successfully. However it may not always reflect the actual content of the
|
|
* corresponding property texture property. This enumeration provides the
|
|
* reason.
|
|
*/
|
|
class PropertyTexturePropertyViewStatus : public PropertyViewStatus {
|
|
public:
|
|
/**
|
|
* @brief This property view was initialized from an invalid
|
|
* {@link PropertyTexture}.
|
|
*/
|
|
static const int ErrorInvalidPropertyTexture = 14;
|
|
|
|
/**
|
|
* @brief This property view is associated with a {@link ClassProperty} of an
|
|
* unsupported type.
|
|
*/
|
|
static const int ErrorUnsupportedProperty = 15;
|
|
|
|
/**
|
|
* @brief This property view does not have a valid texture index.
|
|
*/
|
|
static const int ErrorInvalidTexture = 16;
|
|
|
|
/**
|
|
* @brief This property view does not have a valid sampler index.
|
|
*/
|
|
static const int ErrorInvalidSampler = 17;
|
|
|
|
/**
|
|
* @brief This property view does not have a valid image index.
|
|
*/
|
|
static const int ErrorInvalidImage = 18;
|
|
|
|
/**
|
|
* @brief This property is viewing an empty image.
|
|
*/
|
|
static const int ErrorEmptyImage = 19;
|
|
|
|
/**
|
|
* @brief This property uses an image with multi-byte channels. Only
|
|
* single-byte channels are supported.
|
|
*/
|
|
static const int ErrorInvalidBytesPerChannel = 20;
|
|
|
|
/**
|
|
* @brief The channels of this property texture property are invalid.
|
|
* Channels must be in the range 0-N, where N is the number of available
|
|
* channels in the image. There must be a minimum of one channel. Although
|
|
* more than four channels can be defined for specialized texture
|
|
* formats, this implementation only supports four channels max.
|
|
*/
|
|
static const int ErrorInvalidChannels = 21;
|
|
|
|
/**
|
|
* @brief The channels of this property texture property do not provide
|
|
* the exact number of bytes required by the property type. This may be
|
|
* because an incorrect number of channels was provided, or because the
|
|
* image itself has a different channel count / byte size than expected.
|
|
*/
|
|
static const int ErrorChannelsAndTypeMismatch = 22;
|
|
};
|
|
|
|
/**
|
|
* @brief Attempts to obtain a scalar value from the given span of bytes.
|
|
*
|
|
* @tparam ElementType The scalar value type to read from `bytes`.
|
|
* @param bytes A span of bytes to convert into a scalar value.
|
|
* @returns A value of `ElementType`.
|
|
*/
|
|
template <typename ElementType>
|
|
ElementType assembleScalarValue(const std::span<uint8_t> bytes) noexcept {
|
|
if constexpr (std::is_same_v<ElementType, float>) {
|
|
CESIUM_ASSERT(
|
|
bytes.size() == sizeof(float) &&
|
|
"Not enough channel inputs to construct a float.");
|
|
uint32_t resultAsUint = 0;
|
|
for (size_t i = 0; i < bytes.size(); i++) {
|
|
resultAsUint |= static_cast<uint32_t>(bytes[i]) << i * 8;
|
|
}
|
|
|
|
// Reinterpret the bits as a float.
|
|
return *reinterpret_cast<float*>(&resultAsUint);
|
|
}
|
|
|
|
if constexpr (IsMetadataInteger<ElementType>::value) {
|
|
using UintType = std::make_unsigned_t<ElementType>;
|
|
UintType resultAsUint = 0;
|
|
for (size_t i = 0; i < bytes.size(); i++) {
|
|
resultAsUint |= static_cast<UintType>(bytes[i]) << i * 8;
|
|
}
|
|
|
|
// Reinterpret the bits with the correct signedness.
|
|
return *reinterpret_cast<ElementType*>(&resultAsUint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Attempts to obtain a vector value from the given span of bytes.
|
|
*
|
|
* @tparam ElementType The vector value type to read from `bytes`.
|
|
* @param bytes A span of bytes to convert into a vector value.
|
|
* @returns A value of `ElementType`.
|
|
*/
|
|
template <typename ElementType>
|
|
ElementType assembleVecNValue(const std::span<uint8_t> bytes) noexcept {
|
|
ElementType result = ElementType();
|
|
|
|
const glm::length_t N =
|
|
getDimensionsFromPropertyType(TypeToPropertyType<ElementType>::value);
|
|
using T = typename ElementType::value_type;
|
|
|
|
CESIUM_ASSERT(
|
|
sizeof(T) <= 2 && "Components cannot be larger than two bytes in size.");
|
|
|
|
if constexpr (std::is_same_v<T, int16_t>) {
|
|
CESIUM_ASSERT(
|
|
N == 2 && "Only vec2s can contain two-byte integer components.");
|
|
uint16_t x = static_cast<uint16_t>(bytes[0]) |
|
|
(static_cast<uint16_t>(bytes[1]) << 8);
|
|
uint16_t y = static_cast<uint16_t>(bytes[2]) |
|
|
(static_cast<uint16_t>(bytes[3]) << 8);
|
|
|
|
result[0] = *reinterpret_cast<int16_t*>(&x);
|
|
result[1] = *reinterpret_cast<int16_t*>(&y);
|
|
}
|
|
|
|
if constexpr (std::is_same_v<T, uint16_t>) {
|
|
CESIUM_ASSERT(
|
|
N == 2 && "Only vec2s can contain two-byte integer components.");
|
|
result[0] = static_cast<uint16_t>(bytes[0]) |
|
|
(static_cast<uint16_t>(bytes[1]) << 8);
|
|
result[1] = static_cast<uint16_t>(bytes[2]) |
|
|
(static_cast<uint16_t>(bytes[3]) << 8);
|
|
}
|
|
|
|
if constexpr (std::is_same_v<T, int8_t>) {
|
|
for (size_t i = 0; i < bytes.size(); i++) {
|
|
result[i] = *reinterpret_cast<const int8_t*>(&bytes[i]);
|
|
}
|
|
}
|
|
|
|
if constexpr (std::is_same_v<T, uint8_t>) {
|
|
for (size_t i = 0; i < bytes.size(); i++) {
|
|
result[i] = bytes[i];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Attempts to obtain an array value from the given span of bytes.
|
|
*
|
|
* @tparam T The element type to read from `bytes`.
|
|
* @param bytes A span of bytes to convert into an array value.
|
|
* @returns A \ref PropertyArrayCopy containing the elements read.
|
|
*/
|
|
template <typename T>
|
|
PropertyArrayCopy<T>
|
|
assembleArrayValue(const std::span<uint8_t> bytes) noexcept {
|
|
std::vector<T> result(bytes.size() / sizeof(T));
|
|
|
|
if constexpr (sizeof(T) == 2) {
|
|
for (int i = 0, b = 0; i < result.size(); i++, b += 2) {
|
|
using UintType = std::make_unsigned_t<T>;
|
|
UintType resultAsUint = static_cast<UintType>(bytes[b]) |
|
|
(static_cast<UintType>(bytes[b + 1]) << 8);
|
|
result[i] = *reinterpret_cast<T*>(&resultAsUint);
|
|
}
|
|
} else {
|
|
for (size_t i = 0; i < bytes.size(); i++) {
|
|
result[i] = *reinterpret_cast<const T*>(&bytes[i]);
|
|
}
|
|
}
|
|
|
|
return PropertyArrayCopy<T>(std::move(result));
|
|
}
|
|
|
|
/**
|
|
* @brief Assembles the given type from the provided channel values of sampling
|
|
* a texture.
|
|
*
|
|
* @tparam ElementType The type of element to assemble.
|
|
* @param bytes The byte values of the sampled channels of the texture.
|
|
* @returns The result of \ref assembleScalarValue, \ref assembleVecNValue, or
|
|
* \ref assembleArrayValue depending on `ElementType`.
|
|
*/
|
|
template <typename ElementType>
|
|
PropertyValueViewToCopy<ElementType>
|
|
assembleValueFromChannels(const std::span<uint8_t> bytes) noexcept {
|
|
CESIUM_ASSERT(
|
|
bytes.size() > 0 && "Channel input must have at least one value.");
|
|
|
|
if constexpr (IsMetadataScalar<ElementType>::value) {
|
|
return assembleScalarValue<ElementType>(bytes);
|
|
}
|
|
|
|
if constexpr (IsMetadataVecN<ElementType>::value) {
|
|
return assembleVecNValue<ElementType>(bytes);
|
|
}
|
|
|
|
if constexpr (IsMetadataArray<ElementType>::value) {
|
|
return assembleArrayValue<typename MetadataArrayType<ElementType>::type>(
|
|
bytes);
|
|
}
|
|
}
|
|
|
|
#pragma region Non - normalized property
|
|
|
|
/**
|
|
* @brief A view of the data specified by a {@link PropertyTextureProperty}.
|
|
*
|
|
* Provides utilities to sample the property texture property using texture
|
|
* coordinates. Property values are retrieved from the NEAREST texel without
|
|
* additional filtering applied.
|
|
*
|
|
* @tparam ElementType The type of the elements represented in the property
|
|
* view
|
|
* @tparam Normalized Whether or not the property is normalized. If
|
|
* normalized, the elements can be retrieved as normalized floating-point
|
|
* numbers, as opposed to their integer values.
|
|
*/
|
|
template <typename ElementType, bool Normalized = false>
|
|
class PropertyTexturePropertyView;
|
|
|
|
/**
|
|
* @brief A view of the non-normalized data specified by a
|
|
* {@link PropertyTextureProperty}.
|
|
*
|
|
* Provides utilities to sample the property texture property using texture
|
|
* coordinates.
|
|
*
|
|
* @tparam ElementType The type of the elements represented in the property view
|
|
*/
|
|
template <typename ElementType>
|
|
class PropertyTexturePropertyView<ElementType, false>
|
|
: public PropertyView<ElementType, false>, public TextureView {
|
|
public:
|
|
/**
|
|
* @brief Constructs an invalid instance for a non-existent property.
|
|
*/
|
|
PropertyTexturePropertyView() noexcept
|
|
: PropertyView<ElementType, false>(),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {}
|
|
|
|
/**
|
|
* @brief Constructs an invalid instance for an erroneous property.
|
|
*
|
|
* @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property.
|
|
*/
|
|
PropertyTexturePropertyView(PropertyViewStatusType status) noexcept
|
|
: PropertyView<ElementType, false>(status),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {
|
|
CESIUM_ASSERT(
|
|
this->_status != PropertyTexturePropertyViewStatus::Valid &&
|
|
"An empty property view should not be constructed with a valid status");
|
|
}
|
|
|
|
/**
|
|
* @brief Constructs an instance of an empty property that specifies a default
|
|
* value. Although this property has no data, it can return the default value
|
|
* when \ref get is called. However, \ref getRaw cannot be used.
|
|
*
|
|
* @param classProperty The {@link ClassProperty} this property conforms to.
|
|
*/
|
|
PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
|
|
: PropertyView<ElementType, false>(classProperty),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {
|
|
if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
|
|
// Don't override the status / size if something is wrong with the class
|
|
// property's definition.
|
|
return;
|
|
}
|
|
|
|
if (!classProperty.defaultProperty) {
|
|
// This constructor should only be called if the class property *has* a
|
|
// default value. But in the case that it does not, this property view
|
|
// becomes invalid.
|
|
this->_status =
|
|
PropertyTexturePropertyViewStatus::ErrorNonexistentProperty;
|
|
return;
|
|
}
|
|
|
|
this->_status = PropertyTexturePropertyViewStatus::EmptyPropertyWithDefault;
|
|
}
|
|
|
|
/**
|
|
* @brief Construct a view of the data specified by a {@link PropertyTextureProperty}.
|
|
*
|
|
* @param property The {@link PropertyTextureProperty}
|
|
* @param classProperty The {@link ClassProperty} this property conforms to.
|
|
* @param sampler The {@link Sampler} used by the property.
|
|
* @param image The {@link ImageAsset} used by the property.
|
|
* @param options The options for constructing the view.
|
|
*/
|
|
PropertyTexturePropertyView(
|
|
const PropertyTextureProperty& property,
|
|
const ClassProperty& classProperty,
|
|
const Sampler& sampler,
|
|
const ImageAsset& image,
|
|
const TextureViewOptions& options = TextureViewOptions()) noexcept
|
|
: PropertyView<ElementType, false>(classProperty, property),
|
|
TextureView(
|
|
sampler,
|
|
image,
|
|
property.texCoord,
|
|
property.getExtension<ExtensionKhrTextureTransform>(),
|
|
options),
|
|
_channels(property.channels),
|
|
_swizzle() {
|
|
if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
|
|
return;
|
|
}
|
|
|
|
switch (this->getTextureViewStatus()) {
|
|
case TextureViewStatus::Valid:
|
|
break;
|
|
case TextureViewStatus::ErrorInvalidSampler:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidSampler;
|
|
return;
|
|
case TextureViewStatus::ErrorInvalidImage:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidImage;
|
|
return;
|
|
case TextureViewStatus::ErrorEmptyImage:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorEmptyImage;
|
|
return;
|
|
case TextureViewStatus::ErrorInvalidBytesPerChannel:
|
|
this->_status =
|
|
PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel;
|
|
return;
|
|
case TextureViewStatus::ErrorUninitialized:
|
|
case TextureViewStatus::ErrorInvalidTexture:
|
|
default:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture;
|
|
return;
|
|
}
|
|
|
|
_swizzle.reserve(_channels.size());
|
|
|
|
for (size_t i = 0; i < _channels.size(); ++i) {
|
|
switch (_channels[i]) {
|
|
case 0:
|
|
_swizzle += "r";
|
|
break;
|
|
case 1:
|
|
_swizzle += "g";
|
|
break;
|
|
case 2:
|
|
_swizzle += "b";
|
|
break;
|
|
case 3:
|
|
_swizzle += "a";
|
|
break;
|
|
default:
|
|
CESIUM_ASSERT(
|
|
false && "A valid channels vector must be passed to the view.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the value of the property for the given texture coordinates
|
|
* with all value transforms applied. That is, if the property specifies an
|
|
* offset and scale, they will be applied to the value before the value is
|
|
* returned. The sampler's wrapping mode will be used when sampling the
|
|
* texture.
|
|
*
|
|
* If this property has a specified "no data" value, this will return the
|
|
* property's default value for any elements that equal this "no data" value.
|
|
* If the property did not specify a default value, this returns std::nullopt.
|
|
*
|
|
* @param u The u-component of the texture coordinates.
|
|
* @param v The v-component of the texture coordinates.
|
|
*
|
|
* @return The value of the element, or std::nullopt if it matches the "no
|
|
* data" value
|
|
*/
|
|
std::optional<PropertyValueViewToCopy<ElementType>>
|
|
get(double u, double v) const noexcept {
|
|
if (this->_status ==
|
|
PropertyTexturePropertyViewStatus::EmptyPropertyWithDefault) {
|
|
return propertyValueViewToCopy(this->defaultValue());
|
|
}
|
|
|
|
PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
|
|
|
|
if (value == this->noData()) {
|
|
return propertyValueViewToCopy(this->defaultValue());
|
|
} else if constexpr (IsMetadataNumeric<ElementType>::value) {
|
|
return transformValue(value, this->offset(), this->scale());
|
|
} else if constexpr (IsMetadataNumericArray<ElementType>::value) {
|
|
return transformArray(
|
|
propertyValueCopyToView(value),
|
|
this->offset(),
|
|
this->scale());
|
|
} else {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the raw value of the property for the given texture
|
|
* coordinates. The sampler's wrapping mode will be used when sampling the
|
|
* texture.
|
|
*
|
|
* If this property has a specified "no data" value, the raw value will still
|
|
* be returned, even if it equals the "no data" value.
|
|
*
|
|
* @param u The u-component of the texture coordinates.
|
|
* @param v The v-component of the texture coordinates.
|
|
*
|
|
* @return The value at the nearest pixel to the texture coordinates.
|
|
*/
|
|
|
|
PropertyValueViewToCopy<ElementType>
|
|
getRaw(double u, double v) const noexcept {
|
|
CESIUM_ASSERT(
|
|
this->_status == PropertyTexturePropertyViewStatus::Valid &&
|
|
"Check the status() first to make sure view is valid");
|
|
|
|
std::vector<uint8_t> sample =
|
|
this->sampleNearestPixel(u, v, this->_channels);
|
|
|
|
return assembleValueFromChannels<ElementType>(
|
|
std::span(sample.data(), this->_channels.size()));
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the channels of this property texture property.
|
|
*/
|
|
const std::vector<int64_t>& getChannels() const noexcept {
|
|
return this->_channels;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets this property's channels as a swizzle string.
|
|
*/
|
|
const std::string& getSwizzle() const noexcept { return this->_swizzle; }
|
|
|
|
private:
|
|
std::vector<int64_t> _channels;
|
|
std::string _swizzle;
|
|
};
|
|
|
|
#pragma endregion
|
|
|
|
#pragma region Normalized property
|
|
|
|
/**
|
|
* @brief A view of the normalized data specified by a
|
|
* {@link PropertyTextureProperty}.
|
|
*
|
|
* Provides utilities to sample the property texture property using texture
|
|
* coordinates.
|
|
*/
|
|
template <typename ElementType>
|
|
class PropertyTexturePropertyView<ElementType, true>
|
|
: public PropertyView<ElementType, true>, public TextureView {
|
|
private:
|
|
using NormalizedType = typename TypeToNormalizedType<ElementType>::type;
|
|
|
|
public:
|
|
/**
|
|
* @brief Constructs an invalid instance for a non-existent property.
|
|
*/
|
|
PropertyTexturePropertyView() noexcept
|
|
: PropertyView<ElementType, true>(),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {}
|
|
|
|
/**
|
|
* @brief Constructs an invalid instance for an erroneous property.
|
|
*
|
|
* @param status The code from {@link PropertyTexturePropertyViewStatus} indicating the error with the property.
|
|
*/
|
|
PropertyTexturePropertyView(PropertyViewStatusType status) noexcept
|
|
: PropertyView<ElementType, true>(status),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {
|
|
CESIUM_ASSERT(
|
|
this->_status != PropertyTexturePropertyViewStatus::Valid &&
|
|
"An empty property view should not be constructed with a valid "
|
|
"status");
|
|
}
|
|
|
|
/**
|
|
* @brief Constructs an instance of an empty property that specifies a
|
|
* default value. Although this property has no data, it can return the
|
|
* default value when {@link PropertyTexturePropertyView<ElementType, true>::get} is called.
|
|
* However, {@link PropertyTexturePropertyView<ElementType, true>::getRaw} cannot be used.
|
|
*
|
|
* @param classProperty The {@link ClassProperty} this property conforms to.
|
|
*/
|
|
PropertyTexturePropertyView(const ClassProperty& classProperty) noexcept
|
|
: PropertyView<ElementType, true>(classProperty),
|
|
TextureView(),
|
|
_channels(),
|
|
_swizzle() {
|
|
if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
|
|
// Don't override the status / size if something is wrong with the class
|
|
// property's definition.
|
|
return;
|
|
}
|
|
|
|
if (!classProperty.defaultProperty) {
|
|
// This constructor should only be called if the class property *has* a
|
|
// default value. But in the case that it does not, this property view
|
|
// becomes invalid.
|
|
this->_status =
|
|
PropertyTexturePropertyViewStatus::ErrorNonexistentProperty;
|
|
return;
|
|
}
|
|
|
|
this->_status = PropertyTexturePropertyViewStatus::EmptyPropertyWithDefault;
|
|
}
|
|
|
|
/**
|
|
* @brief Construct a view of the data specified by a {@link PropertyTextureProperty}.
|
|
*
|
|
* @param property The {@link PropertyTextureProperty}
|
|
* @param classProperty The {@link ClassProperty} this property conforms to.
|
|
* @param sampler The {@link Sampler} used by the property.
|
|
* @param image The {@link ImageAsset} used by the property.
|
|
* @param options The options for constructing the view.
|
|
*/
|
|
PropertyTexturePropertyView(
|
|
const PropertyTextureProperty& property,
|
|
const ClassProperty& classProperty,
|
|
const Sampler& sampler,
|
|
const ImageAsset& image,
|
|
const TextureViewOptions& options = TextureViewOptions()) noexcept
|
|
: PropertyView<ElementType, true>(classProperty, property),
|
|
TextureView(
|
|
sampler,
|
|
image,
|
|
property.texCoord,
|
|
property.getExtension<ExtensionKhrTextureTransform>(),
|
|
options),
|
|
_channels(property.channels),
|
|
_swizzle() {
|
|
if (this->_status != PropertyTexturePropertyViewStatus::Valid) {
|
|
return;
|
|
}
|
|
|
|
switch (this->getTextureViewStatus()) {
|
|
case TextureViewStatus::Valid:
|
|
break;
|
|
case TextureViewStatus::ErrorInvalidSampler:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidSampler;
|
|
return;
|
|
case TextureViewStatus::ErrorInvalidImage:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidImage;
|
|
return;
|
|
case TextureViewStatus::ErrorEmptyImage:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorEmptyImage;
|
|
return;
|
|
case TextureViewStatus::ErrorInvalidBytesPerChannel:
|
|
this->_status =
|
|
PropertyTexturePropertyViewStatus::ErrorInvalidBytesPerChannel;
|
|
return;
|
|
case TextureViewStatus::ErrorUninitialized:
|
|
case TextureViewStatus::ErrorInvalidTexture:
|
|
default:
|
|
this->_status = PropertyTexturePropertyViewStatus::ErrorInvalidTexture;
|
|
return;
|
|
}
|
|
|
|
_swizzle.reserve(_channels.size());
|
|
for (size_t i = 0; i < _channels.size(); ++i) {
|
|
switch (_channels[i]) {
|
|
case 0:
|
|
_swizzle += "r";
|
|
break;
|
|
case 1:
|
|
_swizzle += "g";
|
|
break;
|
|
case 2:
|
|
_swizzle += "b";
|
|
break;
|
|
case 3:
|
|
_swizzle += "a";
|
|
break;
|
|
default:
|
|
CESIUM_ASSERT(
|
|
false && "A valid channels vector must be passed to the view.");
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the value of the property for the given texture coordinates
|
|
* with all value transforms applied. That is, if the property specifies an
|
|
* offset and scale, they will be applied to the value before the value is
|
|
* returned. The sampler's wrapping mode will be used when sampling the
|
|
* texture.
|
|
*
|
|
* If this property has a specified "no data" value, and the retrieved
|
|
* element is equal to that value, then this will return the property's
|
|
* specified default value. If the property did not provide a default value,
|
|
* this returns std::nullopt.
|
|
*
|
|
* @param u The u-component of the texture coordinates.
|
|
* @param v The v-component of the texture coordinates.
|
|
*
|
|
* @return The value of the element, or std::nullopt if it matches the "no
|
|
* data" value
|
|
*/
|
|
std::optional<PropertyValueViewToCopy<NormalizedType>>
|
|
get(double u, double v) const noexcept {
|
|
if (this->_status ==
|
|
PropertyTexturePropertyViewStatus::EmptyPropertyWithDefault) {
|
|
return propertyValueViewToCopy(this->defaultValue());
|
|
}
|
|
|
|
PropertyValueViewToCopy<ElementType> value = getRaw(u, v);
|
|
|
|
if (value == this->noData()) {
|
|
return propertyValueViewToCopy(this->defaultValue());
|
|
} else if constexpr (IsMetadataScalar<ElementType>::value) {
|
|
return transformValue<NormalizedType>(
|
|
normalize<ElementType>(value),
|
|
this->offset(),
|
|
this->scale());
|
|
} else if constexpr (IsMetadataVecN<ElementType>::value) {
|
|
constexpr glm::length_t N = ElementType::length();
|
|
using T = typename ElementType::value_type;
|
|
using NormalizedT = typename NormalizedType::value_type;
|
|
return transformValue<glm::vec<N, NormalizedT>>(
|
|
normalize<N, T>(value),
|
|
this->offset(),
|
|
this->scale());
|
|
} else if constexpr (IsMetadataArray<ElementType>::value) {
|
|
using ArrayElementType = typename MetadataArrayType<ElementType>::type;
|
|
if constexpr (IsMetadataScalar<ArrayElementType>::value) {
|
|
return transformNormalizedArray<ArrayElementType>(
|
|
propertyValueCopyToView(value),
|
|
this->offset(),
|
|
this->scale());
|
|
} else if constexpr (IsMetadataVecN<ArrayElementType>::value) {
|
|
constexpr glm::length_t N = ArrayElementType::length();
|
|
using T = typename ArrayElementType::value_type;
|
|
return transformNormalizedVecNArray<N, T>(
|
|
propertyValueCopyToView(value),
|
|
this->offset(),
|
|
this->scale());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the raw value of the property for the given texture
|
|
* coordinates. The sampler's wrapping mode will be used when sampling the
|
|
* texture.
|
|
*
|
|
* If this property has a specified "no data" value, the raw value will
|
|
* still be returned, even if it equals the "no data" value.
|
|
*
|
|
* @param u The u-component of the texture coordinates.
|
|
* @param v The v-component of the texture coordinates.
|
|
*
|
|
* @return The value at the nearest pixel to the texture coordinates.
|
|
*/
|
|
|
|
PropertyValueViewToCopy<ElementType>
|
|
getRaw(double u, double v) const noexcept {
|
|
CESIUM_ASSERT(
|
|
this->_status == PropertyTexturePropertyViewStatus::Valid &&
|
|
"Check the status() first to make sure view is valid");
|
|
|
|
std::vector<uint8_t> sample =
|
|
this->sampleNearestPixel(u, v, this->_channels);
|
|
|
|
return assembleValueFromChannels<ElementType>(
|
|
std::span(sample.data(), this->_channels.size()));
|
|
}
|
|
|
|
/**
|
|
* @brief Gets the channels of this property texture property.
|
|
*/
|
|
const std::vector<int64_t>& getChannels() const noexcept {
|
|
return this->_channels;
|
|
}
|
|
|
|
/**
|
|
* @brief Gets this property's channels as a swizzle string.
|
|
*/
|
|
const std::string& getSwizzle() const noexcept { return this->_swizzle; }
|
|
|
|
private:
|
|
std::vector<int64_t> _channels;
|
|
std::string _swizzle;
|
|
};
|
|
#pragma endregion
|
|
|
|
} // namespace CesiumGltf
|