Add callbacks and tests

This commit is contained in:
Janine Liu 2023-06-29 16:51:07 -04:00
parent 8155617808
commit f3ecde1681
3 changed files with 652 additions and 20 deletions

View File

@ -4,22 +4,26 @@
##### Breaking Changes :mega:
- Views of the data contained by `EXT_feature_metadata` will no longer supported by Cesium Native. The extension will still be parsed, but it will log a warning.
- Batch tables will be converted to `EXT_structural_metadata` instead of `EXT_feature_metadata`.
- In `CesiumGltf`, all generated classes related to `EXT_feature_metadata` are now prefixed with `ExtensionExtFeatureMetadata`. For example, `ClassProperty` has become `ExtensionExtFeatureMetadataClassProperty`. This also extends to the glTF reader and writer.
- In `CesiumGltf`, all generated classes related to `EXT_structural_metadata` have had their `ExtensionExtStructuralMetadata` prefix removed. For example, `ExtensionExtStructuralMetadataClassProperty` has become `ClassProperty`. This also extends to the glTF reader and writer.
- In `CesiumGltf`, `ExtensionExtMeshFeaturesFeatureId` and `ExtensionExtMeshFeaturesFeatureIdTexture` have been renamed to `FeatureId` and `FeatureIdTexture` respectively.
- Replaced `FeatureIDTextureView` with `FeatureIdTextureView`, which views a `FeatureIdTexture` in `EXT_mesh_features`. Feature ID textures from `EXT_feature_metadata` are no longer supported.
- Renamed `FeatureIDTextureViewStatus` to `FeatureIdTextureViewStatus` for consistency.
- Replaced `MetadataFeatureTableView` with `PropertyTableView`, which views a `PropertyTable` in `EXT_structural_metadata`.
- Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid.
- Renamed `MetadataArrayView` to `PropertyArrayView`.
- Replaced `FeatureTextureView` with `PropertyTextureView`, which views a `PropertyTexture` in `EXT_structural_metadata`.
- Renamed `FeatureTextureViewStatus` to `PropertyTextureViewStatus`.
- Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which views a `PropertyTextureProperty` in `EXT_structural_metadata`.
- Replaced `FeatureTexturePropertyView` with `PropertyTexturePropertyView`, which is a templated view of a `PropertyTextureProperty` in `EXT_structural_metadata`.
- Removed `FeatureTexturePropertyComponentType`, `FeatureTexturePropertyChannelOffsets`, and `FeatureTexturePropertyValue`. `PropertyTextureProperty` retrieves the values with the type indicated by its class property.
- Renamed `FeatureTexturePropertyViewStatus` to `PropertyTexturePropertyViewStatus`.
- Refactored `PropertyType` to reflect the values of `type` in a `ClassProperty` from `EXT_structural_metadata`.
- Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`.
Additionally, views of the data contained by `EXT_feature_metadata` will no longer supported by Cesium Native. The extension will still be parsed, but it will log a warning. Batch tables will also be converted to `EXT_structural_metadata` instead of `EXT_feature_metadata`.
##### Additions :tada:
- Added `PropertyTableViewStatus` to indicate whether a `PropertyTableView` is valid.
- Added `PropertyComponentType` to reflect the values of `componentType` in a `ClassProperty` from `EXT_structural_metadata`.
### v0.25.0 - 2023-06-01

View File

@ -84,12 +84,11 @@ public:
* This method will validate the EXT_structural_metadata format to ensure
* {@link PropertyTexturePropertyView} retrieves the correct data. T must be
* a scalar with a supported component type (uint8_t, uint16_t, uint32_t,
* float), or a glm vecN composed of one of the scalar types.
* PropertyArrayViews are unsupported; if the property describes a
* fixed-length array of scalars, T must be a glm vecN of the same length.
* float), a glm vecN composed of one of the scalar types, or a
* PropertyArrayView containing one of the scalar types
*
* @param propertyName The name of the property to retrieve data from
* @return A {@link PropertyTablePropertyView} of the property. If no valid property is
* @return A {@link PropertyTexturePropertyView} of the property. If no valid property is
* found, the property view will be invalid.
*/
template <typename T>
@ -109,6 +108,104 @@ public:
return getPropertyViewImpl<T>(propertyName, *pClassProperty);
}
/**
* @brief Gets a {@link PropertyTexturePropertyView} through a callback that accepts a
* property name and a {@link PropertyTexturePropertyView<T>} that views the data
* of the property with the specified name.
*
* This method will validate the EXT_structural_metadata format to ensure
* {@link PropertyTexturePropertyView} retrieves the correct data. T must be
* a scalar with a supported component type (uint8_t, uint16_t, uint32_t,
* float), a glm vecN composed of one of the scalar types, or a
* PropertyArrayView containing one of the scalar types. If the property is
* invalid, an empty {@link PropertyTexturePropertyView} with an error status
* will be passed to the callback. Otherwise, a valid property view will be
* passed to the callback.
*
* @param propertyName The name of the property to retrieve data from
* @tparam callback A callback function that accepts a property name and a
* {@link PropertyTexturePropertyView<T>}
*/
template <typename Callback>
void
getPropertyView(const std::string& propertyName, Callback&& callback) const {
if (this->_status != PropertyTextureViewStatus::Valid) {
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture));
return;
}
const ClassProperty* pClassProperty = getClassProperty(propertyName);
if (!pClassProperty) {
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorNonexistentProperty));
return;
}
PropertyType type = convertStringToPropertyType(pClassProperty->type);
PropertyComponentType componentType = PropertyComponentType::None;
if (pClassProperty->componentType) {
componentType =
convertStringToPropertyComponentType(*pClassProperty->componentType);
}
if (pClassProperty->array) {
getArrayPropertyViewImpl(
propertyName,
*pClassProperty,
type,
componentType,
std::forward<Callback>(callback));
} else if (type == PropertyType::Scalar) {
getScalarPropertyViewImpl(
propertyName,
*pClassProperty,
componentType,
std::forward<Callback>(callback));
} else if (isPropertyTypeVecN(type)) {
getVecNPropertyViewImpl(
propertyName,
*pClassProperty,
type,
componentType,
std::forward<Callback>(callback));
} else {
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
return;
}
}
/**
* @brief Iterates over each property in the {@link PropertyTexture} with a callback
* that accepts a property name and a {@link PropertyTexturePropertyView<T>} to view
* the data stored in the {@link PropertyTextureProperty}.
*
* This method will validate the EXT_structural_metadata format to ensure
* {@link PropertyTexturePropertyView} retrieves the correct data. T must be
* a scalar with a supported component type (uint8_t, uint16_t, uint32_t,
* float), a glm vecN composed of one of the scalar types, or a
* PropertyArrayView containing one of the scalar types. If the property is
* invalid, an empty {@link PropertyTexturePropertyView} with an error status
* will be passed to the callback. Otherwise, a valid property view will be
* passed to the callback.
*
* @param propertyName The name of the property to retrieve data from
* @tparam callback A callback function that accepts property name and
* {@link PropertyTexturePropertyView<T>}
*/
template <typename Callback> void forEachProperty(Callback&& callback) const {
for (const auto& property : this->_pClass->properties) {
getPropertyView(property.first, std::forward<Callback>(callback));
}
}
private:
template <typename T>
PropertyTexturePropertyView<T> getPropertyViewImpl(
@ -140,6 +237,200 @@ private:
}
}
template <typename Callback>
void getArrayPropertyViewImpl(
const std::string& propertyName,
const ClassProperty& classProperty,
PropertyType type,
PropertyComponentType componentType,
Callback&& callback) const {
// Only scalar arrays are supported.
if (type != PropertyType::Scalar) {
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
}
int64_t count = classProperty.count.value_or(0);
if (count <= 0 || count > 4) {
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
}
switch (componentType) {
case PropertyComponentType::Int8:
callback(
propertyName,
getPropertyViewImpl<PropertyArrayView<int8_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Uint8:
callback(
propertyName,
getPropertyViewImpl<PropertyArrayView<uint8_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Int16:
callback(
propertyName,
getPropertyViewImpl<PropertyArrayView<int16_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Uint16:
callback(
propertyName,
getPropertyViewImpl<PropertyArrayView<uint16_t>>(
propertyName,
classProperty));
break;
default:
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
}
}
template <typename Callback>
void getScalarPropertyViewImpl(
const std::string& propertyName,
const ClassProperty& classProperty,
PropertyComponentType componentType,
Callback&& callback) const {
switch (componentType) {
case PropertyComponentType::Int8:
callback(
propertyName,
getPropertyViewImpl<int8_t>(propertyName, classProperty));
return;
case PropertyComponentType::Uint8:
callback(
propertyName,
getPropertyViewImpl<uint8_t>(propertyName, classProperty));
return;
case PropertyComponentType::Int16:
callback(
propertyName,
getPropertyViewImpl<int16_t>(propertyName, classProperty));
return;
case PropertyComponentType::Uint16:
callback(
propertyName,
getPropertyViewImpl<uint16_t>(propertyName, classProperty));
break;
case PropertyComponentType::Int32:
callback(
propertyName,
getPropertyViewImpl<int32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Uint32:
callback(
propertyName,
getPropertyViewImpl<uint32_t>(propertyName, classProperty));
break;
case PropertyComponentType::Float32:
callback(
propertyName,
getPropertyViewImpl<float>(propertyName, classProperty));
break;
default:
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
break;
}
}
template <typename Callback, glm::length_t N>
void getVecNPropertyViewImpl(
const std::string& propertyName,
const ClassProperty& classProperty,
PropertyComponentType componentType,
Callback&& callback) const {
switch (componentType) {
case PropertyComponentType::Int8:
callback(
propertyName,
getPropertyViewImpl<glm::vec<N, int8_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Uint8:
callback(
propertyName,
getPropertyViewImpl<glm::vec<N, uint8_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Int16:
callback(
propertyName,
getPropertyViewImpl<glm::vec<N, int16_t>>(
propertyName,
classProperty));
break;
case PropertyComponentType::Uint16:
callback(
propertyName,
getPropertyViewImpl<glm::vec<N, uint16_t>>(
propertyName,
classProperty));
break;
default:
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty));
break;
}
}
template <typename Callback>
void getVecNPropertyViewImpl(
const std::string& propertyName,
const ClassProperty& classProperty,
PropertyType type,
PropertyComponentType componentType,
Callback&& callback) const {
const glm::length_t N = getDimensionsFromPropertyType(type);
switch (N) {
case 2:
getVecNPropertyViewImpl<Callback, 2>(
propertyName,
classProperty,
componentType,
std::forward<Callback>(callback));
break;
case 3:
getVecNPropertyViewImpl<Callback, 3>(
propertyName,
classProperty,
componentType,
std::forward<Callback>(callback));
break;
case 4:
getVecNPropertyViewImpl<Callback, 4>(
propertyName,
classProperty,
componentType,
std::forward<Callback>(callback));
break;
default:
callback(
propertyName,
PropertyTexturePropertyView<uint8_t>(
PropertyTexturePropertyViewStatus::ErrorTypeMismatch));
break;
}
}
template <typename T>
PropertyTexturePropertyView<T> createScalarPropertyView(
const ClassProperty& classProperty,
@ -164,17 +455,16 @@ private:
}
// Eight-byte scalar types are unsupported.
if constexpr (
std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> ||
std::is_same_v<T, double>) {
size_t componentSize = getSizeOfComponentType(componentType);
if (componentSize == 0 || componentSize > 4) {
return PropertyTexturePropertyView<T>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty);
} else {
return createPropertyViewImpl<T>(
classProperty,
propertyTextureProperty,
sizeof(T));
}
return createPropertyViewImpl<T>(
classProperty,
propertyTextureProperty,
sizeof(T));
}
template <typename T>
@ -251,14 +541,14 @@ private:
PropertyTexturePropertyViewStatus::ErrorComponentTypeMismatch);
}
// Only uint8 and uint16s are supported.
if (componentType != PropertyComponentType::Uint8 &&
componentType != PropertyComponentType::Uint16) {
// Only up to two-byte components are supported.
size_t componentSize = getSizeOfComponentType(componentType);
if (componentSize == 0 || componentSize > 2) {
return PropertyTexturePropertyView<PropertyArrayView<T>>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty);
}
if (componentType == PropertyComponentType::Uint16 && count > 2) {
if (componentSize * count > 4) {
return PropertyTexturePropertyView<PropertyArrayView<T>>(
PropertyTexturePropertyViewStatus::ErrorUnsupportedProperty);
}

View File

@ -565,6 +565,344 @@ TEST_CASE("Test array PropertyTextureProperty") {
}
}
TEST_CASE("Test callback on invalid property texture view") {
Model model;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
metadata.schema.emplace();
// Property texture has a nonexistent class.
PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back();
propertyTexture.classProperty = "TestClass";
PropertyTextureProperty& propertyTextureProperty =
propertyTexture.properties["TestClassProperty"];
propertyTextureProperty.index = -1;
PropertyTextureView view(model, propertyTexture);
REQUIRE(view.status() == PropertyTextureViewStatus::ErrorClassNotFound);
const ClassProperty* classProperty =
view.getClassProperty("TestClassProperty");
REQUIRE(!classProperty);
uint32_t invokedCallbackCount = 0;
view.getPropertyView(
"TestClassProperty",
[&invokedCallbackCount](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
invokedCallbackCount++;
REQUIRE(
propertyValue.status() ==
PropertyTexturePropertyViewStatus::ErrorInvalidPropertyTexture);
});
REQUIRE(invokedCallbackCount == 1);
}
TEST_CASE("Test callback on invalid PropertyTextureProperty") {
Model model;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
Schema& schema = metadata.schema.emplace();
Class& testClass = schema.classes["TestClass"];
ClassProperty& testClassProperty = testClass.properties["InvalidProperty"];
testClassProperty.type = ClassProperty::Type::SCALAR;
testClassProperty.componentType = ClassProperty::ComponentType::UINT8;
PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back();
propertyTexture.classProperty = "TestClass";
PropertyTextureProperty& propertyTextureProperty =
propertyTexture.properties["InvalidProperty"];
propertyTextureProperty.index = -1;
PropertyTextureView view(model, propertyTexture);
REQUIRE(view.status() == PropertyTextureViewStatus::Valid);
const ClassProperty* classProperty = view.getClassProperty("InvalidProperty");
REQUIRE(classProperty);
classProperty = view.getClassProperty("NonexistentProperty");
REQUIRE(!classProperty);
uint32_t invokedCallbackCount = 0;
auto testCallback = [&invokedCallbackCount](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
invokedCallbackCount++;
REQUIRE(propertyValue.status() != PropertyTexturePropertyViewStatus::Valid);
};
view.getPropertyView("InvalidProperty", testCallback);
view.getPropertyView("NonexistentProperty", testCallback);
REQUIRE(invokedCallbackCount == 2);
}
TEST_CASE("Test callback for scalar PropertyTextureProperty") {
Model model;
std::vector<uint8_t> data = {255, 255, 12, 1, 30, 2, 0, 255};
addTextureToModel(
model,
Sampler::WrapS::CLAMP_TO_EDGE,
Sampler::WrapS::CLAMP_TO_EDGE,
2,
2,
2,
data);
size_t textureIndex = model.textures.size() - 1;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
Schema& schema = metadata.schema.emplace();
Class& testClass = schema.classes["TestClass"];
ClassProperty& testClassProperty = testClass.properties["TestClassProperty"];
testClassProperty.type = ClassProperty::Type::SCALAR;
testClassProperty.componentType = ClassProperty::ComponentType::INT16;
PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back();
propertyTexture.classProperty = "TestClass";
PropertyTextureProperty& propertyTextureProperty =
propertyTexture.properties["TestClassProperty"];
propertyTextureProperty.index = static_cast<int32_t>(textureIndex);
propertyTextureProperty.texCoord = 0;
propertyTextureProperty.channels = {0, 1};
PropertyTextureView view(model, propertyTexture);
REQUIRE(view.status() == PropertyTextureViewStatus::Valid);
const ClassProperty* classProperty =
view.getClassProperty("TestClassProperty");
REQUIRE(classProperty);
REQUIRE(classProperty->type == ClassProperty::Type::SCALAR);
REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT16);
REQUIRE(classProperty->count == std::nullopt);
REQUIRE(!classProperty->array);
std::vector<int16_t> expected{-1, 268, 542, -256};
std::vector<glm::vec2> texCoords{
glm::vec2(0, 0),
glm::vec2(0.5, 0),
glm::vec2(0, 0.5),
glm::vec2(0.5, 0.5)};
uint32_t invokedCallbackCount = 0;
view.getPropertyView(
"TestClassProperty",
[&expected, &texCoords, &invokedCallbackCount](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
invokedCallbackCount++;
if constexpr (std::is_same_v<
PropertyTexturePropertyView<int16_t>,
decltype(propertyValue)>) {
REQUIRE(
propertyValue.status() ==
PropertyTexturePropertyViewStatus::Valid);
for (size_t i = 0; i < expected.size(); ++i) {
glm::vec2& texCoord = texCoords[i];
REQUIRE(propertyValue.get(texCoord[0], texCoord[1]) == expected[i]);
}
} else {
FAIL("getPropertyView returned PropertyTexturePropertyView of "
"incorrect type for TestClassProperty.");
}
});
REQUIRE(invokedCallbackCount == 1);
}
TEST_CASE("Test callback for vecN PropertyTextureProperty") {
Model model;
// clang-format off
std::vector<uint8_t> data = {
255, 255,
12, 1,
30, 2,
0, 255};
// clang-format on
addTextureToModel(
model,
Sampler::WrapS::CLAMP_TO_EDGE,
Sampler::WrapS::CLAMP_TO_EDGE,
2,
2,
2,
data);
size_t textureIndex = model.textures.size() - 1;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
Schema& schema = metadata.schema.emplace();
Class& testClass = schema.classes["TestClass"];
ClassProperty& testClassProperty = testClass.properties["TestClassProperty"];
testClassProperty.type = ClassProperty::Type::VEC2;
testClassProperty.componentType = ClassProperty::ComponentType::INT8;
PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back();
propertyTexture.classProperty = "TestClass";
PropertyTextureProperty& propertyTextureProperty =
propertyTexture.properties["TestClassProperty"];
propertyTextureProperty.index = static_cast<int32_t>(textureIndex);
propertyTextureProperty.texCoord = 0;
propertyTextureProperty.channels = {0, 1};
PropertyTextureView view(model, propertyTexture);
REQUIRE(view.status() == PropertyTextureViewStatus::Valid);
const ClassProperty* classProperty =
view.getClassProperty("TestClassProperty");
REQUIRE(classProperty);
REQUIRE(classProperty->type == ClassProperty::Type::VEC2);
REQUIRE(classProperty->componentType == ClassProperty::ComponentType::INT8);
REQUIRE(classProperty->count == std::nullopt);
REQUIRE(!classProperty->array);
std::vector<glm::i8vec2> expected{
glm::i8vec2(-1, -1),
glm::i8vec2(12, 1),
glm::i8vec2(30, 2),
glm::i8vec2(0, -1)};
std::vector<glm::vec2> texCoords{
glm::vec2(0, 0),
glm::vec2(0.5, 0),
glm::vec2(0, 0.5),
glm::vec2(0.5, 0.5)};
uint32_t invokedCallbackCount = 0;
view.getPropertyView(
"TestClassProperty",
[&expected, &texCoords, &invokedCallbackCount](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
invokedCallbackCount++;
if constexpr (std::is_same_v<
PropertyTexturePropertyView<glm::i8vec2>,
decltype(propertyValue)>) {
REQUIRE(
propertyValue.status() ==
PropertyTexturePropertyViewStatus::Valid);
for (size_t i = 0; i < expected.size(); ++i) {
glm::vec2& texCoord = texCoords[i];
REQUIRE(propertyValue.get(texCoord[0], texCoord[1]) == expected[i]);
}
} else {
FAIL("getPropertyView returned PropertyTexturePropertyView of "
"incorrect type for TestClassProperty.");
}
});
REQUIRE(invokedCallbackCount == 1);
}
TEST_CASE("Test callback for array PropertyTextureProperty") {
Model model;
// clang-format off
std::vector<uint8_t> data = {
254, 0, 253, 1,
10, 2, 40, 3,
30, 0, 0, 2,
10, 2, 255, 4};
// clang-format on
addTextureToModel(
model,
Sampler::WrapS::CLAMP_TO_EDGE,
Sampler::WrapS::CLAMP_TO_EDGE,
2,
2,
4,
data);
size_t textureIndex = model.textures.size() - 1;
ExtensionModelExtStructuralMetadata& metadata =
model.addExtension<ExtensionModelExtStructuralMetadata>();
Schema& schema = metadata.schema.emplace();
Class& testClass = schema.classes["TestClass"];
ClassProperty& testClassProperty = testClass.properties["TestClassProperty"];
testClassProperty.type = ClassProperty::Type::SCALAR;
testClassProperty.componentType = ClassProperty::ComponentType::UINT16;
testClassProperty.array = true;
testClassProperty.count = 2;
PropertyTexture& propertyTexture = metadata.propertyTextures.emplace_back();
propertyTexture.classProperty = "TestClass";
PropertyTextureProperty& propertyTextureProperty =
propertyTexture.properties["TestClassProperty"];
propertyTextureProperty.index = static_cast<int32_t>(textureIndex);
propertyTextureProperty.texCoord = 0;
propertyTextureProperty.channels = {0, 1, 2, 3};
PropertyTextureView view(model, propertyTexture);
REQUIRE(view.status() == PropertyTextureViewStatus::Valid);
const ClassProperty* classProperty =
view.getClassProperty("TestClassProperty");
REQUIRE(classProperty);
REQUIRE(classProperty->type == ClassProperty::Type::SCALAR);
REQUIRE(classProperty->componentType == ClassProperty::ComponentType::UINT16);
REQUIRE(classProperty->array);
REQUIRE(classProperty->count == 2);
std::vector<std::vector<uint16_t>> expected{
{254, 509},
{522, 808},
{30, 512},
{522, 1279}};
std::vector<glm::vec2> texCoords{
glm::vec2(0, 0),
glm::vec2(0.5, 0),
glm::vec2(0, 0.5),
glm::vec2(0.5, 0.5)};
uint32_t invokedCallbackCount = 0;
view.getPropertyView(
"TestClassProperty",
[&expected, &texCoords, &invokedCallbackCount](
const std::string& /*propertyName*/,
auto propertyValue) mutable {
invokedCallbackCount++;
if constexpr (std::is_same_v<
PropertyTexturePropertyView<
PropertyArrayView<uint16_t>>,
decltype(propertyValue)>) {
REQUIRE(
propertyValue.status() ==
PropertyTexturePropertyViewStatus::Valid);
for (size_t i = 0; i < expected.size(); ++i) {
std::vector<uint16_t>& expectedArray = expected[i];
glm::vec2& texCoord = texCoords[i];
PropertyArrayView<uint16_t> array =
propertyValue.get(texCoord[0], texCoord[1]);
REQUIRE(static_cast<size_t>(array.size()) == expectedArray.size());
for (int64_t j = 0; j < array.size(); j++) {
REQUIRE(array[j] == expectedArray[static_cast<size_t>(j)]);
}
}
} else {
FAIL("getPropertyView returned PropertyTexturePropertyView of "
"incorrect type for TestClassProperty.");
}
});
REQUIRE(invokedCallbackCount == 1);
}
TEST_CASE("Test unsupported PropertyTextureProperty classes") {
Model model;
ExtensionModelExtStructuralMetadata& metadata =